This is an exercise of using atomic_flag with acquire/release memory model to implement a very simple mutex.
There are THREADS number of threads, and each thread increment cou LOOP number of times. The threads are synchronized with this simple mutex. However, the code throws exception in thread.join() function. Could someone please enlighten me why this does not work? Thank you in advance!
#include <atomic>
#include <thread>
#include <assert.h>
#include <vector>
using namespace std;
class mutex_simplified {
private:
atomic_flag flag;
public:
void lock() {
while (flag.test_and_set(memory_order_acquire));
}
void unlock() {
flag.clear(memory_order_release);
}
};
mutex_simplified m_s;
int cou(0);
const int LOOP = 10000;
const int THREADS = 1000;
void increment() {
for (unsigned i = 0; i < LOOP; i++) {
m_s.lock();
cou++;
m_s.unlock();
}
}
int main() {
thread a(increment);
thread b(increment);
vector<thread> threads;
for (int i = 0; i < THREADS; i++)
threads.push_back(thread(increment));
for (auto & t : threads) {
t.join();
}
assert(cou == THREADS*LOOP);
}
You are not joining threads a and b. As the result, they might be still running while your program is finishing its execution.
You should either add a.join() and b.join() somewhere, or probably just remove them as the assertion in your main function will fail if you keep them.
Another issue is that you need to explicitly initialize atomic_flag instance in your mutex constructor. It might not cause issues in your example because global variables are zero-initialized, but this might cause issues later.
Related
Could you please check the following code which is not exiting even after condition becomes false?
I'm trying to print numbers from 1 to 10 by first thread, 2 to 20 by second thread likewise & I have 10 threads, whenever count reaches to 100, my program should terminate safely by terminating all threads. But that is not happening, after printing, it stuck up and I don't understand why?
Is there any data race? Please guide.
#include<iostream>
#include<vector>
#include<thread>
#include<mutex>
#include<condition_variable>
std::mutex mu;
int count=1;
bool isDone = true;
std::condition_variable cv;
void Print10(int tid)
{
std::unique_lock<std::mutex> lock(mu);
while(isDone){
cv.wait(lock,[tid](){ return ((count/10)==tid);});
for(int i=0;i<10;i++)
std::cout<<"tid="<<tid<<" count="<<count++<<"\n";
isDone = count<100;//!(count == (((tid+1)*10)+1));
std::cout<<"tid="<<tid<<" isDone="<<isDone<<"\n";
cv.notify_all();
}
}
int main()
{
std::vector<std::thread> vec;
for(int i=0;i<10;i++)
{
vec.push_back(std::thread(Print10,i));
}
for(auto &th : vec)
{
if(th.joinable())
th.join();
}
}
I believe the following code should work for you
#include<iostream>
#include<vector>
#include<thread>
#include<mutex>
#include<condition_variable>
using namespace std;
mutex mu;
int count=1;
bool isDone = true;
condition_variable cv;
void Print10(int tid)
{
unique_lock<std::mutex> lock(mu);
// Wait until condition --> Wait till count/10 = tid
while(count/10 != tid)
cv.wait(lock);
// Core logic
for(int i=0;i<10;i++)
cout<<"tid="<<tid<<" count="<<count++<<"\n";
// Release the current thread thus ensuring serailization
cv.notify_one();
}
int main()
{
std::vector<std::thread> vec;
for(int i=0;i<10;i++)
{
vec.push_back(std::thread(Print10,i));
}
for(auto &th : vec)
{
if(th.joinable())
th.join();
}
return 0;
}
I am trying to implement spsc_queue of boost.
But initialising thread throws error. I cant use both std::thread as well as boost thread.
sharedQueue.hpp
`
#include <stdio.h>
#include <iostream>
#include <queue>
#include <thread>
#include <mutex>
#include <boost/thread.hpp>
#include <boost/lockfree/spsc_queue.hpp>
using namespace std;
class sharedQueue
{
boost::lockfree::spsc_queue<int> lockFreeQ{100};
std::queue<int> comQue;
int head =0;;
int tail = 0;
public:
sharedQueue();
std::mutex lockForQueue;
void write(int writeValue);
int read();
void startTesting();
void TestWrite(int MaxElement);
void lockFreeProduce();
void lockFreeConsume();
void TestLockFreeQueue();
};`
Following is the sharedQueue.cpp
#include "sharedQueue.hpp"
int sharedQueue :: read(){
int readValue;
lockForQueue.lock();
if(!(comQue.empty()))
{
readValue = comQue.front();
comQue.pop();
}
lockForQueue.unlock();
return readValue;
}
void sharedQueue :: write(int writeValue){
lockForQueue.lock();
comQue.push(writeValue);
tail++;
lockForQueue.unlock();
}
void sharedQueue:: startTesting(){
std::cout<<"Size of the que --"<<comQue.size()<<std::endl;
}
void sharedQueue:: TestWrite(int maxEle ){
for(int i = 0 ; i < maxEle; i ++){
write(i);
}
}
void sharedQueue::lockFreeProduce(){
for(int i = 0; i < 10; i++){
cout <<“Produced-- "<< i<<endl;
lockFreeQ.push(i);
}
}
void sharedQueue::lockFreeConsume(){
for(int i = 0; i <10; i++){
lockFreeQ.front();
cout << “ Consume-- "<<lockFreeQ.pop();
}
}
void sharedQueue:: TestLockFreeQueue(){
std::thread t1(lockFreeProduce);
std::thread t2(lockFreeConsume);
t1.join();
t2.join();
} `
I am using Xcode. I have tried changing
C++ Language dialect to c++11 from GNU++11
Standard Library to libc++11 from libstdC++
Please help.
Where am I doing wrong?
You are trying to run a member function as a new thread, not a plain old function. The syntax for member function is different.
void sharedQueue:: TestLockFreeQueue(){
std::thread t1(std::bind(&sharedQueue::lockFreeProduce, this));
std::thread t2(std::bind(&sharedQueue::lockFreeConsume, this));
t1.join();
t2.join();
}
Below answer assumes that we are talking about non-static member function. static member function behaves kind of same way as that of a normal function pointer.
A member function pointer is complex than a plain old function pointer and it cannot be invoked in standalone manner i.e it can only be called when there is an object instance of that class.
See this for an example and read this for better understanding of member function pointers.
An easier way to do it i.e instead of using bind to create a callable object is to use a lambda, C++11 onwards and you should prefer lambda over bind whenever and however possible.
Your example using a lambda:
void sharedQueue:: TestLockFreeQueue(){
std::thread t1([this]() { this->lockFreeProduce(); });
std::thread t2([this]() { this->lockFreeConsume(); });
t1.join();
t2.join();
}
Here I am passing a lambda to the constructor of the thread which creates an anonymous functor structure. The square bracket [...] is the capture list which copies this pointer so that it can be used inside a lambda.
More about lambda can be found here and here.
I am trying to implement lock free queue of user defined data type using boost library, but I am getting wrong result.
Please help me out where I am doing wrong.
#include <boost/lockfree/spsc_queue.hpp>
#include <thread>
#include <iostream>
#include <string.h>
#include <time.h>
class Queue
{
private:
unsigned char *m_data;
int m_len;
public:
Queue(unsigned char *data,int len);
Queue(const Queue &obj);
~Queue();
Queue & operator =(const Queue &obj);
unsigned char *getdata()
{
return m_data;
}
int getint()
{
return m_len;
}
};
Queue::Queue(unsigned char* data, int len)
{
m_len=len;
m_data=new unsigned char[m_len];
memcpy(m_data,data,m_len);
}
Queue::Queue(const Queue& obj)
{
m_len= obj.m_len;
m_data=new unsigned char[m_len];
memcpy(m_data,(unsigned char *)obj.m_data,m_len);
}
Queue::~Queue()
{
delete[] m_data;
m_len=0;
}
Queue & Queue::operator =(const Queue &obj)
{
if(this != &obj)
{
m_len=obj.m_len;
m_data=new unsigned char[m_len];
memcpy(m_data,(unsigned char *)obj.m_data,m_len);
}
return *this;
}
boost::lockfree::spsc_queue<Queue*> q(10);
void produce()
{
int i=0;
unsigned char* data=(unsigned char *)malloc(10);
memset(data,1,9);
Queue obj(data,10);
Queue *pqueue=&obj;
printf("%d\n",pqueue->getint());
q.push(pqueue);
}
void consume()
{
Queue *obj;
q.pop(&obj);
printf("%d\n",obj->getint());
}
int main(int argc, char** argv) {
// std::thread t1{produce};
// std::thread t2{consume};
//
// t1.join();
// t2.join();
produce();
consume();
return 0;
}
As per boost::lockfree::queue requirements I created following in class.
Copy Constructor
Assignment Operator
Destructor
Please let me know if anything other requires.
Thanks.
You're using malloc in C++.
You die.
You have 2 lives left.
Seriously, don't do that. Especially since using it with delete[] is clear cut Undefined Behaviour.
Sadly you lose another life here:
Queue obj(data,10);
Queue *pqueue=&obj;
q.push(pqueue);
You store a pointer to a local. More Undefined Behaviour
You have 1 life left.
Last life at
q.pop(&obj);
You pop using an iterator. It will be treated as an output iterator.
You get a return that indicates the number of elements popped, and items
will be written to &obj[0], &obj[1], &obj[2], etc.
Guess what? Undefined Behaviour.
See also: Boost spsc queue segfault
You died.
You're already dead. But you forsake your afterlife with
printf("%d\n",obj->getint());
Since pop might not have popped anything (the queue may have been empty), this in itself is Undefined Behaviour.
The funny part is, you talk about all these constructor requirements but you store pointers in the lockfree queue...?! Just write it:
typedef std::vector<unsigned char> Data;
class Queue {
private:
Data m_data;
public:
Queue(Data data) : m_data(std::move(data)) {}
Queue() : m_data() {}
unsigned char const *getdata() const { return m_data.data(); }
size_t getint() const { return m_data.size(); }
};
boost::lockfree::spsc_queue<Queue> q(10);
Live On Coliru
Notes:
you need to make the consumer check the return code of pop. The push might not have happened, and lock free queues don't block.
you don't need that contraption. Just pass vectors all the way:
C++ Code
Live On Coliru
#include <boost/lockfree/spsc_queue.hpp>
#include <thread>
#include <iostream>
#include <vector>
typedef std::vector<unsigned char> Queue;
boost::lockfree::spsc_queue<Queue> q(10);
void produce() {
Queue obj(10, 1);
std::cout << __FUNCTION__ << " - " << obj.size() << "\n";
q.push(std::move(obj));
}
void consume() {
Queue obj;
while (!q.pop(obj)) { }
std::cout << __FUNCTION__ << " - " << obj.size() << "\n";
}
int main() {
std::thread t1 {produce};
std::thread t2 {consume};
t1.join();
t2.join();
}
I am trying to convert some existing code to use boost's asio tcp sockets instead of our current implementation. I am able to get a very similar example (of a chat client/server) from the boost site working, but when I attempt to put the code into my own program it stops working.
What I am doing:
Start a server process
The server process makes an empty socket and uses it to listen (with a tcp::acceptor) for TCP connections on a port (10010 for example)
Start a client process
Have the client process create a socket connect to the server's port
When the server sees a client is connecting, it starts listening for data(with async_read) on the socket and creates another empty socket to listen for another TCP connection on the port
When the client sees that the server has connected, it sends 100 bytes of data (with async_write) and waits for the socket to tell it the send is finished...when that happens it prints a message and shuts down
When the server gets notified that its has data that has been read, it prints a message and shuts down
Obviously, I have greatly trimmed this code down from what I'm trying to implement, this is as small as I could make something that reproduces the problem. I'm running on windows and have a visual studio solution file you can get. There's some memory leaks, thread safety problems, and such, but that's because I'm taking stuff out of existing code, so don't worry about them.
Anyway, here's the files one header with some common stuff, a server, and a client.
Connection.hpp:
#ifndef CONNECTION_HPP
#define CONNECTION_HPP
#include
#include
#include
class ConnectionTransfer
{
public:
ConnectionTransfer(char* buffer, unsigned int size) :
buffer_(buffer), size_(size) {
}
virtual ~ConnectionTransfer(void){}
char* GetBuffer(){return buffer_;}
unsigned int GetSize(){return size_;}
virtual void CallbackForFinished() = 0;
protected:
char* buffer_;
unsigned int size_;
};
class ConnectionTransferInProgress
{
public:
ConnectionTransferInProgress(ConnectionTransfer* ct):
ct_(ct)
{}
~ConnectionTransferInProgress(void){}
void operator()(const boost::system::error_code& error){Other(error);}
void Other(const boost::system::error_code& error){
if(!error)
ct_->CallbackForFinished();
}
private:
ConnectionTransfer* ct_;
};
class Connection
{
public:
Connection(boost::asio::io_service& io_service):
sock_(io_service)
{}
~Connection(void){}
void AsyncSend(ConnectionTransfer* ct){
ConnectionTransferInProgress tip(ct);
//sock_->async_send(boost::asio::buffer(ct->GetBuffer(),
// static_cast(ct->GetSize())), tip);
boost::asio::async_write(sock_, boost::asio::buffer(ct->GetBuffer(),
static_cast(ct->GetSize())), boost::bind(
&ConnectionTransferInProgress::Other, tip, boost::asio::placeholders::error));
}
void AsyncReceive(ConnectionTransfer* ct){
ConnectionTransferInProgress tip(ct);
//sock_->async_receive(boost::asio::buffer(ct->GetBuffer(),
// static_cast(ct->GetSize())), tip);
boost::asio::async_read(sock_, boost::asio::buffer(ct->GetBuffer(),
static_cast(ct->GetSize())), boost::bind(
&ConnectionTransferInProgress::Other, tip, boost::asio::placeholders::error));
}
boost::asio::ip::tcp::socket& GetSocket(){return sock_;}
private:
boost::asio::ip::tcp::socket sock_;
};
#endif //CONNECTION_HPP
BoostConnectionClient.cpp:
#include "Connection.hpp"
#include
#include
#include
#include
using namespace boost::asio::ip;
bool connected;
bool gotTransfer;
class FakeTransfer : public ConnectionTransfer
{
public:
FakeTransfer(char* buffer, unsigned int size) : ConnectionTransfer(buffer, size)
{
}
void CallbackForFinished()
{
gotTransfer = true;
}
};
void ConnectHandler(const boost::system::error_code& error)
{
if(!error)
connected = true;
}
int main(int argc, char* argv[])
{
connected = false;
gotTransfer = false;
boost::asio::io_service io_service;
Connection* conn = new Connection(io_service);
tcp::endpoint ep(address::from_string("127.0.0.1"), 10011);
conn->GetSocket().async_connect(ep, ConnectHandler);
boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));
while(!connected)
{
boost::this_thread::sleep(boost::posix_time::millisec(1));
}
std::cout (angle brackets here) "Connected\n";
char data[100];
FakeTransfer* ft = new FakeTransfer(data, 100);
conn->AsyncReceive(ft);
while(!gotTransfer)
{
boost::this_thread::sleep(boost::posix_time::millisec(1));
}
std::cout (angle brackets here) "Done\n";
return 0;
}
BoostConnectionServer.cpp:
#include "Connection.hpp"
#include
#include
#include
#include
using namespace boost::asio::ip;
Connection* conn1;
bool conn1Done;
bool gotTransfer;
Connection* conn2;
class FakeAcceptor
{
public:
FakeAcceptor(boost::asio::io_service& io_service, const tcp::endpoint& endpoint)
:
io_service_(io_service),
acceptor_(io_service, endpoint)
{
conn1 = new Connection(io_service_);
acceptor_.async_accept(conn1->GetSocket(),
boost::bind(&FakeAcceptor::HandleAccept, this, conn1,
boost::asio::placeholders::error));
}
void HandleAccept(Connection* conn, const boost::system::error_code& error)
{
if(conn == conn1)
conn1Done = true;
conn2 = new Connection(io_service_);
acceptor_.async_accept(conn2->GetSocket(),
boost::bind(&FakeAcceptor::HandleAccept, this, conn2,
boost::asio::placeholders::error));
}
boost::asio::io_service& io_service_;
tcp::acceptor acceptor_;
};
class FakeTransfer : public ConnectionTransfer
{
public:
FakeTransfer(char* buffer, unsigned int size) : ConnectionTransfer(buffer, size)
{
}
void CallbackForFinished()
{
gotTransfer = true;
}
};
int main(int argc, char* argv[])
{
boost::asio::io_service io_service;
conn1Done = false;
gotTransfer = false;
tcp::endpoint endpoint(tcp::v4(), 10011);
FakeAcceptor fa(io_service, endpoint);
boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));
while(!conn1Done)
{
boost::this_thread::sleep(boost::posix_time::millisec(1));
}
std::cout (angle brackets here) "Accepted incoming connection\n";
char data[100];
FakeTransfer* ft = new FakeTransfer(data, 100);
conn1->AsyncReceive(ft);
while(!gotTransfer)
{
boost::this_thread::sleep(boost::posix_time::millisec(1));
}
std::cout (angle brackets here) "Success!\n";
return 0;
}
I've searched around a bit, but haven't had much luck. As far as I can tell, I'm almost exactly matching the sample, so it must be something small that I'm overlooking.
Thanks!
In your client code, your ConnectHandler() callback function just sets a value and then returns, without posting any more work to the io_service. At that point, that async_connect() operation is the only work associated with the io_service; so when ConnectHandler() returns, there is no more work associated with the io_service. Thus the background thread's call to io_service.run() returns, and the thread exits.
One potential option would be to call conn->AsyncReceive() from within ConnectHandler(), so that the async_read() gets called prior to the ConnectHandler() returning and thus the background thread's call to io_service.run() won't return.
Another option, the more trivial one, would be to instantiate an io_service::work instance prior to creating your thread to call io_service::run (technically, you could do this at any point prior to the io_service.run() call's returning):
...
// some point in the main() method, prior to creating the background thread
boost::asio::io_service::work work(io_service)
...
This is documented in the io_service documentation:
Stopping the io_service from running out of work
Some applications may need to prevent an io_service object's run() call from returning when there is no more work to do. For example, the io_service may be being run in a background thread that is launched prior to the application's asynchronous operations. The run() call may be kept running by creating an object of type io_service::work:
http://www.boost.org/doc/libs/1_43_0/doc/html/boost_asio/reference/io_service.html
What does it mean to move a object from one thread to another in Qt using moveToThread? Everything seems to work even before using moveToThread, which moves the object from one thread (GUI thread) to a another thread ( worked) and Qt:connect calls the appropriate slot on object.
Is there any difference because of where the object lives, GUI thread or the worker thread?
EDIT:
I made a small program, but I don't understand how QThread works along with Signal and slot function, I would appreciate if you could explain what is the use of moveToThread with the example
#include <QtGui/QApplication>
#include <QPushButton>
#include <QHBoxLayout>
#include <QLineEdit>
#include <QString>
#include "mythread.h"
//GUI calls a thread to do some job and sub update the text box once it is done
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
QHBoxLayout * pH = new QHBoxLayout(&w);
QPushButton * pushButton = new QPushButton("asdad");
QLineEdit * lineEdit = new QLineEdit("AAA");
pH->addWidget(pushButton);
pH->addWidget(lineEdit);
w.setLayout(pH);
w.show();
MyThread thread;
qDebug("Thread id %d",(int)QThread::currentThreadId());
QObject::connect(pushButton,SIGNAL(clicked()),&thread,SLOT(callRun())) ;
QObject::connect(&thread,SIGNAL(signalGUI(QString)),lineEdit,SLOT(setText(QString)));
return a.exec();
}
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QMutex>
class MyThread : public QThread
{
Q_OBJECT
public:
MyThread();
public slots:
void callRun();
void run();
signals:
void signalGUI(QString);
private:
QMutex mutex;
};
#endif // MYTHREAD_H
#include "mythread.h"
#include <QDebug>
#include <QString>
#include <QMutexLocker>
MyThread::MyThread()
{
}
void MyThread::callRun()
{
qDebug("in thread");
if(!isRunning())
{
this->start(LowestPriority);
exec();
}
else
{
run();
}
}
void MyThread::run()
{
QMutexLocker fn_scope(&mutex);
static int a = 0;
++a;
qDebug("Thread id inside run %d",(int)QThread::currentThreadId());
this->sleep(3);
static QString number;
QString temp;
number += temp.setNum(a);
emit signalGUI(number);
}
Take a look at Signals and slots across threads. If you always use signals and slots to communicate with the worker thread, Qt handles the moveToThread for you if it's needed and you used the correct connection.
Edit: I would guess the article's author was seeing his problem since he was calling start in the constructor before the thread was actually created. In other words, don't trust third-party code blindly.
Edit: In response to your comment, look at the Mandelbrot example, under the MandelbrotWidget Class Implementation header:
With queued connections, Qt must store a copy of the arguments that were passed to the signal so that it can pass them to the slot later on. Qt knows how to take of copy of many C++ and Qt types, but QImage isn't one of them. We must therefore call the template function qRegisterMetaType() before we can use QImage as parameter in queued connections.
I believe this is slightly outdated, here are the valid meta types. Since signals and slots across threads use queued connections, you should not have to do the moveToThread calls in most cases.
Edit:
I will try to explain things with a similar example:
mythread.h:
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QMutex>
class MyThread : public QThread
{
Q_OBJECT
protected:
virtual void run();
signals:
void signalGUI(QString);
};
#endif // MYTHREAD_H
mythread.cpp:
#include "mythread.h"
#include <QString>
void MyThread::run()
{
qDebug("Thread id inside run %d",(int)QThread::currentThreadId());
static int run = 0;
QString temp = QString("Run: %1").arg(run++);
qDebug("String address inside run %p", &temp);
emit signalGUI(temp);
}
mylineedit.h
#ifndef MYLINEEDIT_H
#define MYLINEEDIT_H
#include <QLineEdit>
class MyLineEdit : public QLineEdit
{
Q_OBJECT
public:
explicit MyLineEdit(QWidget *parent = 0);
public slots:
void setText(const QString &string);
};
#endif // MYLINEEDIT_H
mylineedit.cpp
#include "mylineedit.h"
#include <QThread>
MyLineEdit::MyLineEdit(QWidget *parent) :
QLineEdit(parent)
{
}
void MyLineEdit::setText(const QString &string)
{
qDebug("Thread id inside setText %d",(int)QThread::currentThreadId());
qDebug("String address inside setText %p\n", &string);
QLineEdit::setText(string);
}
main.cpp:
#include <QApplication>
#include <QPushButton>
#include <QHBoxLayout>
#include "mythread.h"
#include "mylineedit.h"
//GUI calls a thread to do some job and sub update the text box once it is done
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
QHBoxLayout * pH = new QHBoxLayout(&w);
QPushButton * pushButton = new QPushButton("Run Thread", &w);
MyLineEdit * lineEdit = new MyLineEdit(&w);
pH->addWidget(pushButton);
pH->addWidget(lineEdit);
w.show();
MyThread thread;
qDebug("Thread id %d",(int)QThread::currentThreadId());
QObject::connect(pushButton,SIGNAL(clicked()),&thread,SLOT(start())) ;
QObject::connect(&thread,SIGNAL(signalGUI(const QString&)),lineEdit,SLOT(setText(const QString&)));
return a.exec();
}
Sample output after clicking button:
Thread id 1088110320
Thread id inside run 1093176208
String address inside run 0x41288350
Thread id inside setText 1088110320
String address inside setText 0x974af58
As you can see, the run thread is different than the main GUI thread. Also, even though you pass a const reference to a QString, since it crosses thread boundaries it copies it.
I strongly encourage you to read Threads and QObject.
The QThread::start() method creates the thread and calls your run() implementation. If you want to handle events or received signals on the thread you have to call QThread::exec() inside your run() implementation. You should never call run() explicitly and you should never call exec() outside of run().
The owner thread makes a difference only when a slot is connected to a signal with the connection type other than Qt::DirectConnection. Then Qt will ensure that the slot runs on the owner thread, but for that the owner thread must be running an event loop with QThread::exec(). In this case calling myObj.moveToThread(myThread) will ensure that myObj slots run on the thread myThread.
The thread object belongs to the thread where it was created, not on the thread that it manages (and where the run method will run). So when you connect a signal to a thread object's slot, that slot will run in the thread where the thread object was created unless you call moveToThread().
When moving an object between threads, you decide which event loop it belongs to. When making connections inside a thread, the signaling code directly calls each one of the slots (having to wait for them to finish). Signalling across thread boundaries places the signal call on the event loop, letting the slot's thread make the call to the slot when ready.
Making direct calls between threads requires you to make sure that your functions are reentrant. You must also make sure to protect your data using mutexes or semaphores and at the same time avoid race conditions.
In the article, I guess that the delay is due to the call being direct, i.e. not at all processed in the background (but I only skimmed the text).
#include <QtGui/QApplication>
#include <QPushButton>
#include <QHBoxLayout>
#include <QLineEdit>
#include <QString>
#include "mythread.h"
//GUI calls a thread to do some job and sub update the text box once it is done
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
QHBoxLayout * pH = new QHBoxLayout(&w);
QPushButton * pushButton = new QPushButton("asdad");
QLineEdit * lineEdit = new QLineEdit("AAA");
pH->addWidget(pushButton);
pH->addWidget(lineEdit);
w.setLayout(pH);
w.show();
MyThread thread;
thread.moveToThread(&thread);
thread.start();
qDebug("Thread id %d",(int)QThread::currentThreadId());
QObject::connect(pushButton,SIGNAL(clicked()),&thread,SLOT(callRun()),Qt::QueuedConnection) ;
QObject::connect(&thread,SIGNAL(signalGUI(QString)),lineEdit,SLOT(setText(QString)),Qt::DirectConnection);
return a.exec();
}
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QMutex>
class MyThread : public QThread
{
Q_OBJECT
public:
MyThread();
public slots:
void callRun();
void run();
signals:
void signalGUI(QString);
private:
QMutex mutex;
};
#endif // MYTHREAD_H
#include "mythread.h"
#include <QDebug>
#include <QString>
#include <QMutexLocker>
MyThread::MyThread()
{
}
void MyThread::callRun()
{
QMutexLocker fn_scope(&mutex);
static int a = 0;
++a;
qDebug("Thread id inside run %d",(int)QThread::currentThreadId());
this->sleep(3);
static QString number;
QString temp;
number += temp.setNum(a);
emit signalGUI(number);
}
void MyThread::run()
{
exec();
}
New thread object is created and the thread object is moved to the same thread. Signals are now across threads and connection type are both queue and it works as expected.
some objects only can be used on the owner thread. for example if you create and socket object in one thread and you want to send and recv data in another thread it is'nt possible. therefore one solution is to move your object from one thread to other and operate on it.