Write to QTcpSocket fails with different thread error - multithreading

I have created a simple threaded TCP server which collects 3 lines read from the socket, and then tries to echo them back to the socket. The function echoCommand below crashes.
#include "fortunethread.h"
#include <QtNetwork>
#include <QDataStream>
FortuneThread::FortuneThread(int socketDescriptor, QObject *parent)
: QThread(parent), socketDescriptor(socketDescriptor), in(0)
{
}
void FortuneThread::run()
{
tcpSocketPtr = new QTcpSocket;
if (!tcpSocketPtr->setSocketDescriptor(socketDescriptor)) {
emit error(tcpSocketPtr->error());
return;
}
in = new QDataStream(tcpSocketPtr);
connect(tcpSocketPtr, SIGNAL(readyRead()), this, SLOT(readCommand()) );
QThread::exec();
}
void FortuneThread::echoCommand()
{
QString block;
QTextStream out(&block, QIODevice::WriteOnly);
for (QStringList::Iterator it = commandList.begin(); it != commandList.end(); ++it) {
out << "Command: " << *it << endl;
}
out << endl;
tcpSocketPtr->write(block.toUtf8());
tcpSocketPtr->disconnectFromHost();
tcpSocketPtr->waitForDisconnected();
}
void FortuneThread::readCommand()
{
while (tcpSocketPtr->canReadLine())
{
commandList << (tcpSocketPtr->readLine()).trimmed();
}
if (commandList.size() > 2)
{
echoCommand();
}
}
and here is the file where I connect up the slots/signals:
#include "fortuneserver.h"
#include "fortunethread.h"
#include <stdlib.h>
FortuneServer::FortuneServer(QObject *parent)
: QTcpServer(parent)
{
}
void FortuneServer::incomingConnection(qintptr socketDescriptor)
{
QString fortune = fortunes.at(qrand() % fortunes.size());
FortuneThread *thread = new FortuneThread(socketDescriptor, this);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
during or after the socket write, with this error:
**QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNativeSocketEngine(0x7f19cc002720), parent's thread is FortuneThread(0x25411d0), current thread is QThread(0x220ff90)**
Since I create the tcpSocketPtr in the run() function, I know it is in the same thread as this function. Why would the socket write fail? I should point out that the write is succeeding since I see the output on the telnet window...but still the socket write fails...
Just more info...I found that I should NOT put a slot in a QThread..not sure how to get around this, but here is my class definiation:
class FortuneThread : public QThread
{
Q_OBJECT
public:
FortuneThread(int socketDescriptor, QObject *parent);
void run();
signals:
void error(QTcpSocket::SocketError socketError);
private slots:
void readCommand();
private:
void echoCommand();
int socketDescriptor;
QDataStream *in;
QStringList commandList;
QTcpSocket *tcpSocketPtr;
};

Related

Regarding thread communication to post task back from called child thread to main thread

I have a requirement to post a task from child thread to main thread back. I am creating child thread from the main thread and posting tasks over there. But after receiving few callbacks from common API, I need to execute a few particular tasks on main thread only like proxy creation, etc. so in such a scenario, I have to communicate with the main thread and need to post that particular task on the main thread. I have designed LoopingThread.cpp as mentioned below and communicating with the main for posting tasks on that:
LoopingThread.cpp:
#include <iostream>
#include "loopingThread.hpp"
using namespace std;
LoopingThread::LoopingThread() : thread(nullptr), scheduledCallbacks() {
}
LoopingThread::~LoopingThread() {
if (this->thread) {
delete this->thread;
}
}
void LoopingThread::runCallbacks() {
this->callbacksMutex.lock();
if (this->scheduledCallbacks.size() > 0) {
std::thread::id threadID = std::this_thread::get_id();
std::cout<<"inside runCallback()threadId:"<<threadID<<std::endl;
// This is to allow for new callbacks to be scheduled from within a callback
std::vector<std::function<void()>> currentCallbacks = std::move(this->scheduledCallbacks);
this->scheduledCallbacks.clear();
this->callbacksMutex.unlock();
for (auto callback : currentCallbacks) {
//callback();
//this->callback();
int id = 1;
this->shared_func(id);
}
} else {
this->callbacksMutex.unlock();
}
}
void LoopingThread::shared_func(int id)
{
std::thread::id run_threadID = std::this_thread::get_id();
std::cout<<"shared_func: "<<run_threadID<<std::endl;
this->callbacksMutex.lock();
if (id == 0)
std::cout<<"calling from main,id: "<<id<<std::endl;
else if (id == 1)
std::cout<<"calling from child,id: "<<id<<std::endl;
this->callbacksMutex.unlock();
}
void LoopingThread::run() {
std::thread::id run_threadID = std::this_thread::get_id();
std::cout<<"Child_run_threadID: "<<run_threadID<<std::endl;
for (;;) {
this->runCallbacks();
// Run the tick
if (!this->tick()) {
std::cout<<"Run the tick"<<std::endl;
break;
}
}
// Run pending callbacks, this might result in an infinite loop if there are more
// callbacks scheduled from within scheduled callbacks
this->callbacksMutex.lock();
while (this->scheduledCallbacks.size() > 0) {
std::cout<<"inside scheduledCallbacks.size() > 0"<<std::endl;
this->callbacksMutex.unlock();
this->runCallbacks();
this->callbacksMutex.lock();
}
this->callbacksMutex.unlock();
}
void LoopingThread::scheduleCallback(std::function<void()> callback) {
std::cout<<"inside schedulecallback"<<std::endl;
this->callbacksMutex.lock();
this->scheduledCallbacks.push_back(callback);
this->callbacksMutex.unlock();
}
void LoopingThread::start() {
if (!this->thread) {
this->thread = new std::thread(&LoopingThread::run, this);
//std::thread::id threadID = std::this_thread::get_id();
//std::cout<<"creating thread: "<<threadID<<std::endl;
}
}
void LoopingThread::join() {
if (this->thread && this->thread->joinable()) {
this->thread->join();
std::cout<<"joining thread"<<std::endl;
}
}
**main.cpp:**
#include <thread>
#include <chrono>
#include <iostream>
#include <mutex>
#include <string>
#include "loopingThread.hpp"
using namespace std;
std::mutex stdoutMutex;
// Example usage of LoopingThread with a classic MainThread:
class MainThread : public LoopingThread {
private:
MainThread();
public:
virtual ~MainThread();
static MainThread& getInstance();
virtual bool tick();
};
MainThread::MainThread() {}
MainThread::~MainThread() {}
MainThread& MainThread::getInstance() {
// Provide a global instance
static MainThread instance;
return instance;
}
bool MainThread::tick() {
// std::cout<<"main thread:"<<threadID<<std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
stdoutMutex.lock();
std::cout << "tick" << std::endl;
stdoutMutex.unlock();
// Return false to stop this thread
return true;
}
void doLongAsyncTask() {
std::thread longTask([] () {
stdoutMutex.lock();
std::cout << "Beginning long task..." <<std::endl;
stdoutMutex.unlock();
std::this_thread::sleep_for(std::chrono::seconds(2));
stdoutMutex.lock();
std::cout << "Long task finished!" << std::endl;
stdoutMutex.unlock();
MainThread::getInstance().scheduleCallback([] () {
stdoutMutex.lock();
std::cout << "This is called within the main thread!" << std::endl <<
"No need to worry about thread safety or " <<
"race conditions here" << std::endl;
stdoutMutex.unlock();
});
});
longTask.detach();
}
int main() {
doLongAsyncTask();
MainThread::getInstance().start();
MainThread::getInstance().join();
MainThread::getInstance().run();
}
Now suppose child thread receives any task of creating proxy then It needs to post that task back to the main thread. How to achieve this scenario?

cannot handle QNetworkAccessManager::finised signal in multithreading

I want to serialize network requests using QNetworkAccessManager. For achieving it i wrote such class:
#ifndef CLIENT_H
#define CLIENT_H
#include <queue>
#include <mutex>
#include <condition_variable>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkRequest>
class Client : public QObject
{
Q_OBJECT
struct RequestRecord
{
RequestRecord(QString u, int o):url(u),operation(o){}
QString url;
int operation;
};
std::mutex mutex;
std::queue<RequestRecord*> requests;
QNetworkAccessManager *manager;
bool running;
std::condition_variable cv;
public:
Client():manager(nullptr){}
~Client()
{
if(manager)
delete manager;
}
void request_cppreference()
{
std::unique_lock<std::mutex> lock(mutex);
requests.push(new RequestRecord("http://en.cppreference.com",0));
cv.notify_one();
}
void request_qt()
{
std::unique_lock<std::mutex> lock(mutex);
requests.push(new RequestRecord("http://doc.qt.io/qt-5/qnetworkaccessmanager.html",1));
cv.notify_one();
}
void process()
{
manager = new QNetworkAccessManager;
connect(manager,&QNetworkAccessManager::finished,[this](QNetworkReply *reply)
{
std::unique_lock<std::mutex> lock(mutex);
RequestRecord *front = requests.front();
requests.pop();
delete front;
reply->deleteLater();
});
running = true;
while (running)
{
std::unique_lock<std::mutex> lock(mutex);
cv.wait(lock);
RequestRecord *front = requests.front();
manager->get(QNetworkRequest(QUrl(front->url)));
}
}
};
#endif // CLIENT_H
As one can see, there are 2 methods for requesting data from network and method process, which should be called in separate thread.
I'm using this class as follows:
Client *client = new Client;
std::thread thr([client](){
client->process();
});
std::this_thread::sleep_for(std::chrono::seconds(1));
client->request_qt();
std::this_thread::sleep_for(std::chrono::milliseconds(1));
client->request_cppreference();
This example illustrate 2 consecutive requests to network from one thread and processing of these request in another. All works fine except my lambda is never called. Requests are sent (checked it using wireshark), but i cannot get replies. What is the cause?
as #thuga suppose the problem was in event loop. My thread always waiting on cv and thus cannot process events, little hack solve the problem:
void process()
{
manager = new QNetworkAccessManager;
connect(manager,&QNetworkAccessManager::finished,[this](QNetworkReply *reply)
{
std::unique_lock<std::mutex> lock(mutex);
RequestRecord *front = requests.front();
requests.pop();
delete front;
qDebug() << reply->readAll();
processed = true;
reply->deleteLater();
});
running = true;
while (running)
{
{
std::unique_lock<std::mutex> lock(mutex);
cv.wait(lock);
if(requests.size() > 0 && processed)
{
RequestRecord *front = requests.front();
manager->get(QNetworkRequest(QUrl(front->url)));
processed = false;
QtConcurrent::run([this]()
{
while (running)
{
cv.notify_one();
msleep(10);
}
});
}
}
QCoreApplication::processEvents();
}
}
};
it's not beautiful obvious since it is using 3 threads instead of 2, but it is Qt with this perfect phrase:
QUrl QNetworkReply::url() const Returns the URL of the content
downloaded or uploaded. Note that the URL may be different from that
of the original request. If the
QNetworkRequest::FollowRedirectsAttribute was set in the request, then
this function returns the current url that the network API is
accessing, i.e the url emitted in the QNetworkReply::redirected
signal.

QT5 Cross-thread communication, slot not called in "this" context

I have an object MainWorker ran as a separate thread thanks to moveToThread method.
MainWorker has a member SubWorker which is also ran as a separate thread. Both threads are working in infinite loops.
The idea is, MainWorker and SubWorker both perform some separate computations. Whenever SubWorker is done computing, it should notify MainWorker with the result.
Therefore I intuitively made first connection between signal emitted by SubWorker and a slot of MainWorker, but it wasn't working, so I made two more connections to rule out some potential problems:
connect(subWorker, &SubWorker::stuffDid, this, &MainWorker::reportStuff)); //1
connect(subWorker, &SubWorker::stuffDid, subWorker, &SubWorker::reportStuff); //2
connect(this, &MainWorker::stuffDid, this, &MainWorker::reportStuffSelf); //3
It seems, that what is not working is exactly what I need - cross thread communication, because connection 2 and 3 works as expected. My question is: How do I make connection 1 work?
Edit: Apparently, after Karsten's explanation, it is clear that infinite loop blocks the EventLoop. So the new question is, how can I send messages (signals, whatever) from an infinite loop thread to its parent thread?
I am new to Qt, there is a high chance that I got it completely wrong. Here goes the minimal (not)working example:
MainWorker.h
class MainWorker : public QObject
{
Q_OBJECT
public:
MainWorker() : run(false) {}
void doStuff()
{
subWorker = new SubWorker;
subWorkerThread = new QThread;
subWorker->moveToThread(subWorkerThread);
connect(subWorkerThread, &QThread::started, subWorker, &SubWorker::doStuff);
if(!connect(subWorker, &SubWorker::stuffDid, this, &MainWorker::reportStuff)) qDebug() << "connect failed";
connect(subWorker, &SubWorker::stuffDid, subWorker, &SubWorker::reportStuff);
connect(this, &MainWorker::stuffDid, this, &MainWorker::reportStuffSelf);
subWorkerThread->start();
run = true;
while(run)
{
QThread::currentThread()->msleep(200);
emit stuffDid();
}
}
private:
bool run;
QThread* subWorkerThread;
SubWorker* subWorker;
signals:
void stuffDid();
public slots:
void reportStuff()
{
qDebug() << "MainWorker: SubWorker did stuff";
}
void reportStuffSelf()
{
qDebug() << "MainWorker: MainWorker did stuff (EventLoop is not blocked)";
}
};
SubWorker.h
class SubWorker : public QObject
{
Q_OBJECT
public:
SubWorker() : run(false) {}
void doStuff()
{
run = true;
while(run)
{
qDebug() << "SubWorker: Doing stuff...";
QThread::currentThread()->msleep(1000);
emit stuffDid();
}
}
private:
bool run;
public slots:
void reportStuff()
{
qDebug() << "SubWorker: SubWorker did stuff";
}
signals:
void stuffDid();
};
main.cpp
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MainWorker *mainWorker = new MainWorker;
QThread *mainWorkerThread = new QThread;
mainWorker->moveToThread(mainWorkerThread);
QObject::connect(mainWorkerThread, &QThread::started, mainWorker, &MainWorker::doStuff);
mainWorkerThread->start();
return a.exec();
}

Creating a QWidget in a non-GUI thread

Yes, I know that you cannot use GUI things from non-GUI threads. However, it seems reasonable to be able to create a QWidget object, send it to the GUI thread, and then send signals to it. However, when I try to do so, I get errors that widgets cannot be moved. However, this seems to works:
#include <iostream>
#include <QApplication>
#include <QtConcurrentRun>
#include <QDialog>
class BasicViewer : public QDialog
{
Q_OBJECT
public:
void Function(const float a)
{
std::cout << a << std::endl;
}
};
struct BasicViewerWrapper : public QObject
{
Q_OBJECT
public:
BasicViewer WrappedBasicViewer;
void Function(const float a)
{
WrappedBasicViewer.Function(a);
}
};
#include "main.moc" // For CMake's automoc
void Function2()
{
BasicViewerWrapper basicViewerWrapper;
basicViewerWrapper.moveToThread(QCoreApplication::instance()->thread());
basicViewerWrapper.Function(2.0f);
}
void Function1()
{
Function2();
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QtConcurrent::run(Function1);
std::cout << "End" << std::endl;
return app.exec();
}
I have created a wrapper class with the same API as the QWidget that stores an instance of the QWidget I wanted to create directly. I AM allowed to create that wrapper, move it to the GUI thread, and then use it. My question is, is there a way to do this without having to write this wrapper? It seems quite tedious, and since the concept works, I don't understand why it cannot be done directly. Any thoughts?
----------- EDIT ---------------
The first example was a bad one, because it did not attempt to do anything with GUI elements. This example indeed generates "Cannot create children for a parent that is in a different thread."
#include <iostream>
#include <QApplication>
#include <QtConcurrentRun>
#include <QMessageBox>
class BasicViewer : public QMessageBox
{
Q_OBJECT
public:
};
struct BasicViewerWrapper : public QObject
{
Q_OBJECT
public:
BasicViewer WrappedBasicViewer;
void exec()
{
WrappedBasicViewer.exec();
}
};
#include "main.moc" // For CMake's automoc
void Function2()
{
BasicViewerWrapper basicViewerWrapper;
basicViewerWrapper.moveToThread(QCoreApplication::instance()->thread());
basicViewerWrapper.exec();
}
void Function1()
{
Function2();
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QtConcurrent::run(Function1);
return app.exec();
}
----------- EDIT 2 ----------------
I thought this would work, since the member object gets created after the thread of the Wrapper has been moved:
#include <iostream>
#include <QApplication>
#include <QtConcurrentRun>
#include <QMessageBox>
class BasicViewer : public QMessageBox
{
Q_OBJECT
public:
};
struct BasicViewerWrapper : public QObject
{
Q_OBJECT
public:
BasicViewer* WrappedBasicViewer;
void exec()
{
WrappedBasicViewer->exec();
}
void create()
{
WrappedBasicViewer = new BasicViewer;
}
};
#include "main.moc" // For CMake's automoc
void Function2()
{
BasicViewerWrapper basicViewerWrapper;
basicViewerWrapper.moveToThread(QCoreApplication::instance()->thread());
basicViewerWrapper.create();
basicViewerWrapper.exec();
}
void Function1()
{
Function2();
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QtConcurrent::run(Function1);
return app.exec();
}
Unfortunately, it does not. Can anyone explain why?
--------------- EDIT 3 --------------------
I'm unsure why this works? It uses a signal to trigger the GUI component, but isn't the GUI object (the QDialog) still created in the non-GUI thread?
#include <iostream>
#include <QApplication>
#include <QtConcurrentRun>
#include <QMessageBox>
class DialogHandler : public QObject
{
Q_OBJECT
signals:
void MySignal(int* returnValue);
public:
DialogHandler()
{
connect( this, SIGNAL( MySignal(int*) ), this, SLOT(MySlot(int*)), Qt::BlockingQueuedConnection );
}
void EmitSignal(int* returnValue)
{
emit MySignal(returnValue);
}
public slots:
void MySlot(int* returnValue)
{
std::cout << "input: " << *returnValue << std::endl;
QMessageBox* dialog = new QMessageBox;
dialog->addButton(QMessageBox::Yes);
dialog->addButton(QMessageBox::No);
dialog->setText("Test Text");
dialog->exec();
int result = dialog->result();
if(result == QMessageBox::Yes)
{
*returnValue = 1;
}
else
{
*returnValue = 0;
}
delete dialog;
}
};
#include "main.moc" // For CMake's automoc
void MyFunction()
{
DialogHandler* dialogHandler = new DialogHandler;
dialogHandler->moveToThread(QCoreApplication::instance()->thread());
int returnValue = -1;
dialogHandler->EmitSignal(&returnValue);
std::cout << "returnValue: " << returnValue << std::endl;
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QtConcurrent::run(MyFunction);
std::cout << "End" << std::endl;
return app.exec();
}
Qt insists that widgets be created within the GUI thread. It disables moving widgets to different threads to prevent them from existing outside of the GUI thread. Your example above does not, in fact, move the BasicViewer to a different thread; it only moves BasicViewerWrapper to a different thread. You can see this if you print out the pointer to the containing thread within BasicViewerWrapper::Function and BasicViewer::Function:
std::cout << std::hex << thread() << std::endl;
If you really wish to trigger the creation of widgets from outside the GUI thread, it is more advisable for other threads to notify the GUI thread to create the widgets that you desire. You can either emit a signal from the non-GUI thread that connects to a slot in the GUI thread that creates the widgets, or you can invoke a function within the GUI thread to create the widgets for you using QMetaObject::invokeMethod.
EDIT
Unfortunately, there is no way to invoke a method in a different thread other than QMetaObject::invokeMethod if you are attempting to perform the invocation outside of a QObject. In the past, I've tried to tackle readability by placing the method invocation in a separate class or function, but admittedly, it's not perfect.
Your 3rd example is not working because QObject::moveToThread is not synchronous. Control must return to the destination thread's event loop before the object is actually moved to the destination thread. As such, you probably need a combination of a sleep statement and a call to QCoreApplication::processEvents after calling moveToThread. After these calls, you should probably call basicViewerWrapper::create() and basicViewerWrapper::exec() via QMetaObject::invokeMethod.

QThread issues. Crash after 2058 runs

Following thread code runs 2058 times, after that it crashes. Can somebody help me figure out why? The idea of the program is create some class in main thread, pass it to worker thread, thread fills needed data and pass data back to main thread. This example crashes after 2058 runs, however it should go indefinately. I've run it 20 times, always the same number. In version of reduced qWarning() calls (print simple line each 100 runs) thread gets executed 3000 times. So I guess it does not depend on amount of qWarning() calls. And why pointer address for SharedData *d is always the same?
main.cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TestThread* thread = new TestThread();
MainWindow w(thread);
w.show();
delete thread;
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QtGui/QMainWindow>
#include <QThread>
#include <QHash>
class SharedData
{
public:
SharedData();
QString var;
QHash<QString, QString> hash;
};
class TestThread : public QThread
{
Q_OBJECT
public:
TestThread(QObject *parent = 0);
void doWork(SharedData* _data);
void doCrash(QHash<QString, QString>* hash);
signals:
void completed(SharedData* d);
private:
SharedData* data;
protected:
void run();
};
namespace Ui
{
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(TestThread* t, QWidget *parent = 0);
~MainWindow();
void runThread();
public slots:
void jobDone(SharedData* req);
private:
Ui::MainWindow *ui;
TestThread* t;
int runcount;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug.h>
TestThread::TestThread(QObject *parent) : QThread(parent)
{
}
void TestThread::run()
{
qWarning() << "Thread running";
data->var = "hello";
doCrash(&data->hash);
emit completed(data);
}
void TestThread::doWork(SharedData* _data)
{
data = _data;
qWarning() << "Attempting to start";
if(!isRunning())
{
run();
}
else
{
qWarning() << "Oops. Already running";
}
}
void TestThread::doCrash(QHash<QString, QString>* hash)
{
hash->insert("test", "123");
/*
QHashIterator<QString, QString> i(*hash);
while (i.hasNext()) {
i.next();
qWarning() << i.key() + ":" + i.value();
}
*/
}
SharedData::SharedData()
{
}
void MainWindow::jobDone(SharedData* req)
{
qWarning() << "RETURNED";
qWarning() << "var: " << req->var << " addr: " << &req->var;
qWarning() << "cnt: " << req->hash.count() << " addr: " << &req->hash;
QHashIterator<QString, QString> i(req->hash);
while (i.hasNext()) {
i.next();
qWarning() << i.key() + ":" + i.value();
}
delete req;
runThread();
}
MainWindow::MainWindow(TestThread* _t, QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
t = _t;
connect(t, SIGNAL(completed(SharedData*)), this, SLOT(jobDone(SharedData*)));
runcount = 0;
runThread();
}
void MainWindow::runThread()
{
SharedData* d = new SharedData();
d->var = "test";
runcount++;
qWarning() << "Run count: " << runcount;
qWarning() << "CREATING THREAD";
qWarning() << "var: " << d->var << " addr: " << &d->var;
qWarning() << "cnt: " << d->hash.count() << " addr: " << &d->hash;
t->doWork(d);
}
MainWindow::~MainWindow()
{
delete ui;
}
You shouldn't deleting your TestThread instance in main.cpp (comment out "delete thread;" string) !
As vnm has pointed out, the cause of the crash is most likely the delete thread; instruction in main.cpp: when you call w.show() it will return immediately, it is the exec() call that will start the event loop and block, but by then it is too late as the thread has already been deleted.
I would declare the thread as a non-pointer member of the main window instead of passing it as a parameter, this way the compiler will do the cleanup and initialization for you.
An even simpler solution would be to use QtConcurrent::run. By doing this you will eliminate all the explicit treading code, but still get the benefits of multi threading.

Resources