PDA

View Full Version : Data sharing between threads



havij000
7th July 2013, 06:53
Hello everybody,

I am new to the qt an now I am trying to write a multithread program. In this program I need to share specific data between the threads. I define these data in a specific class but as I want each elements of this class I recieved the undifined error.:crying::confused:

what should I do?

Thanks

ChrisW67
7th July 2013, 11:28
Unless you give us information we cannot help. We have no idea what your code looks like, what the errors are, what you have tried to "fix" it, what this has to do with Qt, what this has to do with threads etc.

havij000
8th July 2013, 06:38
Thanks ChrisW67,

first of all I want to know how should I share a specific data such as a data structure or a static array between different threads as a global data. for example I need a buffer which is fill up with one thread and sorted with another thread and showed with a third thread.

anda_skoa
8th July 2013, 09:35
You share the data just like you would in a single thread case, e.g. pass by pointer or reference, have a global variable or accessible through a singleton.
The only difference is that you need to protect against concurrent access.

Cheers,
_

P.S.: posting to a three year old thread instead of adding information to your new one is going to annoy people, scatter necessary information, increase the time until your problem can be understood

havij000
9th July 2013, 06:16
Dear anda_skoa,

thanks for your reply. I am just sharing like in single thread case, defining a new class and in this class I declear my required data as the class members and by creating objects of this class in different threads, shared the data but I face this (error: undefined reference to `Data_Class::prime_rcv_buff_flag')

this is the class that I share the data with it:


#ifndef DATA_CLASS_H
#define DATA_CLASS_H

#include <QObject>


class Data_Class : public QObject
{
Q_OBJECT
public:
explicit Data_Class(QObject *parent = 0);

struct A2D_hdr
{
unsigned short PRF_Num;//PRF Number
unsigned short Frame_Num;//Frame Number
unsigned short Video_Length;//video packet total length
unsigned short EOP;//End of packet if all bit set 1
unsigned long rsrvd;//Reserved
};

struct DDC_packet
{
struct A2D_hdr DDC_HDR;
unsigned short A2D_Data[700];//1400 byte data

};

struct MAC_Data_HDR
{
unsigned short CMD;//command
unsigned short Base_Addrs;//Base Address
unsigned short Length;//Length for burst operation in word
};

struct MAC_Data
{
struct MAC_Data_HDR total_HDR;

struct DDC_packet total_data;

};

struct PKT_CMPLT_DATA//*************need to add header to it.
{
bool valid;
bool total_set;
bool total_modify;

unsigned short arvd_pkts;// for cheking that which has not arrived yet

unsigned short prf_num;

struct MAC_Data_HDR total_header;//hazf shavad
//struct A2D_hdr cmplt_data_hdr;

unsigned char total_hdr[6];
unsigned char A2Dhdr[36];

bool part1_set;
bool part1_modified;
struct A2D_hdr cmplt_data_hdr_prt_1;
unsigned short cmplt_data_prt_1[700];//bayad hazf shavad
unsigned char CmpltData_prt_1[1400];

bool part2_set;
bool part2_modified;
struct A2D_hdr cmplt_data_hdr_prt_2;
unsigned short cmplt_data_prt_2[700];//bayad hazf shavad
unsigned char CmpltData_prt_2[1400];

bool part3_set;
bool part3_modified;
struct A2D_hdr cmplt_data_hdr_prt_3;
unsigned short cmplt_data_prt_3[700];//bayad hazf shavad
unsigned char CmpltData_prt_3[1400];

bool part4_set;
bool part4_modified;
struct A2D_hdr cmplt_data_hdr_prt_4;
unsigned short cmplt_data_prt_4[700];//bayad hazf shavad
unsigned char CmpltData_prt_4[1400];

bool part5_set;
bool part5_modified;
struct A2D_hdr cmplt_data_hdr_prt_5;
unsigned short cmplt_data_prt_5[700];//bayad hazf shavad
unsigned char CmpltData_prt_5[1400];

bool part6_set;
bool part6_modified;
struct A2D_hdr cmplt_data_hdr_prt_6;
unsigned short cmplt_data_prt_6[700];//bayad hazf shavad
unsigned char CmpltData_prt_6[1400];

bool part7_set;
bool part7_modified;
struct A2D_hdr cmplt_data_hdr_prt_7;
unsigned short cmplt_data_prt_7[700];//bayad hazf shavad
unsigned char CmpltData_prt_7[1400];

};


struct eth_Header
{
unsigned char dest_addr[6];
unsigned char src_addr[6];
unsigned short lng;

struct MAC_Data data;
};

//data structure for saving DDC_1 data
static PKT_CMPLT_DATA Q_smpl_pckt_ddc_1[4];
static PKT_CMPLT_DATA I_smpl_pckt_ddc_1[4];
static PKT_CMPLT_DATA Ramp_smpl_pckt_ddc_1[4];
static PKT_CMPLT_DATA Rare_smpl_pckt_ddc_1[4];

//data structure for saving DDC_2 data
static PKT_CMPLT_DATA Q_smpl_pckt_ddc_2[4];
static PKT_CMPLT_DATA I_smpl_pckt_ddc_2[4];
static PKT_CMPLT_DATA Ramp_smpl_pckt_ddc_2[4];
static PKT_CMPLT_DATA Rare_smpl_pckt_ddc_2[4];

//data structure for sending requsts

static eth_Header rqst_pkt;

static unsigned char prime_rcv_buff[20][1514];
static bool prime_rcv_buff_flag[20];


signals:

public slots:

};

#endif // DATA_CLASS_H







and use it in other threads as below in the header of the thread



Data_Class *data_rcv_child;


and in the .cpp of the thread:


Recive_Thread::Recive_Thread(QObject *parent) :
QThread(parent)
{

data_rcv_child = new Data_Class(this);
}


void Recive_Thread::run()
{

while(true)
{
.
.
.
memcpy(&data_rcv_child->prime_rcv_buff + prime_rcv_counter, buffer,sizeof(buffer));

data_rcv_child->prime_rcv_buff_flag[prime_rcv_counter] = true;

.
.


}
}



and face the error that I mentioned above
:confused:

ChrisW67
9th July 2013, 07:55
You have declared that a static array of bools exists. Where and how have you defined that array?

I really don't think you understand what the storage type of "static" is doing.

havij000
9th July 2013, 09:15
I defined the static bool array in class Data_Class header. Am I wrong here?

As I have to check its value in other threads, I declear static type, thus the array keep its last change and I can check it in other threads.

ChrisW67
9th July 2013, 12:54
No, you declared the array in the Data_Class header. You have declared the static therefore there is only one array shared between all objects of that class (regardless of thread or whether objects of that class exist). Space for the static array is not allocated by creating new instances of Data_Class objects. A cpp source file needs to define the static variable and provide somewhere for the single array to be stored so the linker can connect every attempt to use it to that storage.

If you are expecting a separate array for each thread then you certainly do not want "static" members.

This has nothing to do with threads or Qt: it is C++.

havij000
10th July 2013, 06:03
no I dont want separate array for each thread. the data is the same for all of them and each thread should do one part of the operation on these data.

My main problem here is that when I want to use any field of the class in each thread I face a the undifine error.
I need to know the how is the exact way of data sharing between threads?

ChrisW67
10th July 2013, 08:05
My main problem here is that when I want to use any field of the class in each thread I face a the undifine error.
Yes, and I have already told you what you need to do to fix it: define the storage for the array.
In the header


class Stuff {
public:
static bool thingies[10]; // this is a declaration that a static array exists.
};

in a cpp file:


bool Stuff::thingies[10]; // this defines where the storage for the static array exists.

The static storage class has nothing to do with whether the array is accessible from one or more threads and is unnecessary.

I offer a complete example of a multi threaded Qt program sharing data between threads in the hope of dragging this thread into some relevance to Qt:


#include <QCoreApplication>
#include <QTimer>
#include <QThread>
#include <QMutex>
#include <QMutexLocker>
#include <QDebug>


struct Data {
Data(): mutex(new QMutex), value(0) { }
~Data() { delete mutex; }

QMutex *mutex;
int value;
};


class Writer: public QObject
{
Q_OBJECT
Data *d;
public:
Writer(Data *data, QObject *p = 0):
QObject(p),
d(data)
{ }
signals:
void finished();
public slots:
void process() {
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), SLOT(tick()));
timer->setInterval(1000);
timer->start();

QTimer::singleShot(8000, this, SIGNAL(finished())); // self-destruct in 8 secs
}

void tick() {
qDebug() << "Try writing";
QMutexLocker locker(d->mutex);
d->value++;
qDebug() << "Written" << d->value;
}
};

class Reader: public QObject
{
Q_OBJECT
int n;
Data *d;
public:
Reader(int number, Data *data, QObject *p = 0):
QObject(p),
n(number),
d(data)
{ }
signals:
void finished();
public slots:
void process() {
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), SLOT(tick()));
timer->setInterval(1000);
timer->start();

QTimer::singleShot(10000, this, SIGNAL(finished())); // self-destruct in 10 secs
}

void tick() {
qDebug() << n << "Try reading";
QMutexLocker locker(d->mutex);
qDebug() << n << "Read" << d->value;
}
};

int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);

Data data; // the shared data

QThread* thread = new QThread(qApp);
Writer* writer = new Writer(&data);
writer->moveToThread(thread);
QObject::connect(thread, SIGNAL(started()), writer, SLOT(process()));
QObject::connect(writer, SIGNAL(finished()), thread, SLOT(quit()));
QObject::connect(writer, SIGNAL(finished()), writer, SLOT(deleteLater()));
QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();

for (int n = 0; n < 3; ++n) {
thread = new QThread(qApp);
Reader* reader = new Reader(n, &data);
reader->moveToThread(thread);
QObject::connect(thread, SIGNAL(started()), reader, SLOT(process()));
QObject::connect(reader, SIGNAL(finished()), thread, SLOT(quit()));
QObject::connect(reader, SIGNAL(finished()), reader, SLOT(deleteLater()));
QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}

return app.exec();
}
#include "main.moc"

tfgo777
11th July 2013, 12:46
We are trying to study the available item example in one line into another line, and we have a limitation to sustain fixed varying...What is the new update?

havij000
13th July 2013, 06:53
I used the




bool Stuff::thingies[10];




in the class .cpp file but I face the

error: invalid use of qualified-name 'Data_Class:: prime_rcv_buff_flag'
:confused:

ChrisW67
13th July 2013, 09:03
9283
That was an example not a cut-n-paste prescription. If you actually put that line in your code it would not be addressing your static member problem and certainly not be generating that error message. Error messages without context are absolutely useless to us.

It is all academic anyway because you do not need the static storage class to solve the problem. I have already shown a complete example of data shared between threads that I suggest you read.

Added after 5 minutes:


We are trying to study the available item example in one line into another line, and we have a limitation to sustain fixed varying...What is the new update?
Is this a Google Translate (or similar) of a genuine question? It does not seem to have anything to do with this thread.

VikMorroHun
14th July 2013, 00:53
I offer a complete example of a multi threaded Qt program sharing data between threads in the hope of dragging this thread into some relevance to Qt:


I had the same problem but your code is a bit complex to me. Here is another solution. Original code and article can be found here (http://www.altdevblogaday.com/2012/01/11/safer-data-sharing-between-threads/).



//widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QThread>
#include <QMutex>

struct Shared {
volatile int shared_var;
};

class Thread : public QThread
{
Q_OBJECT

signals:
void finishProgress(Shared *);
void startProgress();

public:
Thread();
void run();

private slots:
void on_threadReceived(Shared * main_thread_access);

private:
QMutex shared_mutex;
Shared shared;
Shared *main_thread_access;
Shared *worker_thread_access;
};

class Widget : public QWidget
{
Q_OBJECT

signals:
void sender(Shared *);

public:
explicit Widget(QWidget *parent = 0);
~Widget();

private slots:
void on_thread_progressOccured(Shared * worker_thread_access);

private:
Ui::Widget *ui;
Thread threadA;
Shared shared;
Shared *main_thread_access;
Shared *worker_thread_access;

#endif // WIDGET_H

//widget.cpp
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
connect(this, SIGNAL(sender(Shared *)), &threadA, SLOT(on_threadReceived(Shared *)), Qt::QueuedConnection); //send shared data to different thread
connect(&threadA, SIGNAL(finishProgress(Shared *)), this, SLOT(on_thread_progressOccured(Shared * )), Qt::QueuedConnection); //receive shared data from different thread
main_thread_access = &shared;
worker_thread_access = NULL;
main_thread_access->shared_var = 2;
}


//somewhere in the program
emit sender(main_thread_access); //we send a signal which carries the shared data to a different thread

void Thread::run() {
worker_thread_access->shared_var += 3; //modify the shared data
shared_mutex.unlock();
emit finishProgress(worker_thread_access);
quit();
}

void Widget::on_thread_progressOccured(Shared * worker_thread_access) {
main_thread_access->shared_var = worker_thread_access->shared_var;
if (main_thread_access->shared_var == 2)
QMessageBox::information(this, tr("Error"), tr("Nothing changed on different thread."));
else //if (main_thread_access->shared_var == 3)
QMessageBox::information(this, tr("Ok"), tr("Everything's fine, shared_var == %1.").arg(QString::number(main_thread_access->shared_var)));
//continuous calling of the other thread keeps incrementing the shared data by three.
}

void Thread::on_threadReceived(Shared * main_thread_access) {
//qDebug() << "thread start";
shared_mutex.lock(); //Right now I'm not sure about this, maybe a QMutexLocker approach would be better. Or not.
worker_thread_access->shared_var = main_thread_access->shared_var;
//qDebug() << main_thread_access->shared_var;
start(); //we start the other thread here
}

havij000
14th July 2013, 07:13
one more question, how can I start different threads simultaneously in the ui by clicking a sing bottun?

VikMorroHun
14th July 2013, 19:00
one more question, how can I start different threads simultaneously in the ui by clicking a sing bottun?

You have to add the necessary yourThread->start() commands or signals to that button's code.


I had the same problem but your code is a bit complex to me. Here is another solution. Original code and article can be found here (http://www.altdevblogaday.com/2012/01/11/safer-data-sharing-between-threads/).



An important thing is missing from the above code, but I can't edit it anymore.

Thread::Thread() {
worker_thread_access = &shared;
}

anda_skoa
20th July 2013, 18:42
Oh dear!

Please people, if you are doing multi thread programming, make sure you have read at least about the basics for that topic.

The synchronization mechanism, e.g. the QMutex, obviously needs to be along side the shared data. Using different instances a QMutex for a single instance of shared data does not help you in any way.

It is really very simple:

1) create a data class that protects its data by using QMutex
2) create an instance of that data class
3) pass the data to as many threads as you'd like
4) start the threads

Cheers,
_

havij000
21st July 2013, 10:13
another question

how should I set the value of different fields of a data structure that I have defined in the header of my thread class?



#ifndef WRT_RQST_THREAD_H
#define WRT_RQST_THREAD_H

#include <QThread>
#include "DDC_Header.h"

class Wrt_Rqst_Thread : public QThread
{
Q_OBJECT
public:
explicit Wrt_Rqst_Thread(QObject *parent = 0);

void run(QString str, int lngth);
bool Stop;


private:

struct wrt_rqst_buff
{
unsigned char Dest_MAC[6];
unsigned char Src_MAC[6];
unsigned char Eth_Length[2];//should be 0x0800
unsigned char Wrt_Cmd[2];//should be 0x0000
unsigned char Base_Addrs[2];
unsigned char Data_Length[2];//should be 0x02EB
unsigned char data[1494];//should be set all az 0

}*wrt_buff;

signals:

public slots:

};

#endif // WRT_RQST_THREAD_H




I used


*(unsigned short *) wrt_buff->Data_Length = 0x0080;


but I faced the memory segmentation error.
:confused:

anda_skoa
21st July 2013, 13:18
Did you create an instance of the data structure?

Cheers,
_

havij000
27th July 2013, 06:13
How Can I start different threads simultaneously by clicking on a simple buttom?

ChrisW67
27th July 2013, 08:01
The same way you start a thread any other time. You have examples in this thread already.

havij000
29th July 2013, 07:44
Did you create an instance of the data structure?


Thanks you were right

havij000
12th August 2013, 08:10
How should I creat a child from my main header class and share it between different threads?
:confused:

anda_skoa
12th August 2013, 09:30
Can you post some updated code snippets so that we are sure we are talking about the same classes?

Cheers,
_

havij000
13th August 2013, 09:27
yes of course due to the limitation of the file size and the number of files that can be uploaded I 'll upload some of my codes,

I have already uploaded my header class this the data which I need to share between the threads :

regards

anda_skoa
13th August 2013, 12:10
Well, first you data class doesn't have to be a QObject.
Second, your data is public but the mutex is private. Other code could access the data but cannot access the mutex to protect the data access.

So: remove the QObject inheritance, you don't need it, and make the data members private and make sure getters and setters lock the mutex before access the data members (see also QMutexLocker)

As for passing the data, well, for example passing to the constructor of your thread class:



Data_class *data = new Data_class;
MyThread *thread1 = new MyThread( data );
MyThread *thread2 = new MyThread( data );


Cheers,
_

havij000
14th August 2013, 06:03
Dear anda_skoa,

Thanks for your response.

I remove the Qobject, but I have a question about
making the data member private

now as its member are public I just include its header in other threads and use its data member, change them or use them, but how sould I use them when I make them private?


And one more question, where should I add these parts of codes?




Data_class *data = new Data_class;
MyThread *thread1 = new MyThread( data );
MyThread *thread2 = new MyThread( data );



Thanks

Regards,

havij000
14th August 2013, 08:28
Dear anda_skoa,
in this part of code;




MyThread *thread1 = new MyThread( data );



cannot send a pointer it should be


MyThread *thread1 = new MyThread(Qobject *parent);


is there any problem if make the mutex public?
:confused:

anda_skoa
14th August 2013, 09:39
I remove the Qobject, but I have a question about

now as its member are public I just include its header in other threads and use its data member, change them or use them, but how sould I use them when I make them private?

You can make the mutex public as well and ensure that it is being used everywhere you access any of the other members. Making the members private is usually just the preferred way to be safe, because all accessors of the class can then be checked to use the mutex and users of the class don't have to care about it anymore.

For example if you have a simple data class


class DataClass
{
public:
int m_value;
QMutex m_mutex;
}

and two functions accessing


void doSomething(DataClass *data)
{
QMutexLocker locker( &data->m_mutex );
data->m_value = 1;
}

void doSomethingElse(DataClass *data)
{
QMutexLocker locker( &data->m_mutex );
data->m_value = 2;
}

Then both use cases need to be aware of the locking.

On the other hand, if your members are private, only the accessors in DataClass need to take care of that:


class DataClass
{
private:
int m_value;
QMutex m_mutex;

public:
void setValue(int value) {
QMutexLocker locker(&m_mutex);
m_value = value;
}
}

void doSomething(DataClass *data)
{
data->setValue( 1 );
}

void doSomethingElse(DataClass *data)
{
data->setValue( 2 );
}



And one more question, where should I add these parts of codes?


Well, whereever you are currently creating your threads.



in this part of code;


MyThread *thread1 = new MyThread( data );

cannot send a pointer it should be


MyThread *thread1 = new MyThread(Qobject *parent);



Obviously MyThread needs to have a constructor that takes a pointer to your data class, right?
MyThread is a QThread subclass that you control, you add whatever you want to its API.

Cheers,
_