Thread Programming in C++/CLR - multithreading

I am really struggling with Thread programming in Visual C++/CLR. I have searched a lot and found lots of material on the internet including the official resources however i am still confused. There are very few resources for C++/CLR. Most of them are for C# or old style C++. I try to run this simple code. I choose a new project of type clr console applicatioN and place the following code there but i am getting errors which i am not understading.
// thread_clr.cpp : main project file.
#include "stdafx.h"
using namespace System;
using namespace System;
using namespace System::Threading;
class MessagePrinter;
// class ThreadTester demonstrates basic threading concepts
class ThreadTester
{
static int Main()
{
// Create and name each thread. Use MessagePrinter's
// Print method as argument to ThreadStart delegate.
MessagePrinter printer1 = gcnew MessagePrinter();
Thread thread1 = gcnew Thread ( gcnew ThreadStart( printer1.Print ) );
thread1.Name = "thread1";
MessagePrinter printer2 = gcnew MessagePrinter();
Thread thread2 = gcnew Thread ( gcnew ThreadStart( printer2.Print ) );
thread2.Name = "thread2";
MessagePrinter printer3 = gcnew MessagePrinter();
Thread thread3 = gcnew Thread ( gcnew ThreadStart( printer3.Print ) );
thread3.Name = "thread3";
Console.WriteLine( "Starting threads" );
// call each thread's Start method to place each
// thread in Started state
thread1.Start();
thread2.Start();
thread3.Start();
Console.WriteLine( "Threads started\n" );
} // end method Main
}; // end class ThreadTester
class MessagePrinter
{
private int sleepTime;
private static Random random = gcnew Random();
// constructor to initialize a MessagePrinter object
public MessagePrinter()
{
// pick random sleep time between 0 and 5 seconds
sleepTime = random.Next( 5001 );
}
//controls Thread that prints message
public void Print()
{
// obtain reference to currently executing thread
Thread current = Thread.CurrentThread;
// put thread to sleep for sleepTime amount of time
Console.WriteLine(current.Name + " going to sleep for " + sleepTime );
Thread.Sleep ( sleepTime );
// print thread name
Console.WriteLine( current.Name + " done sleeping" );
} // end method Print
} // end class MessagePrinter
Please help. Or better still please guide me to some tutorials or something to that affect. I understand SO is not a tutorial site and i am not asking one but i would appreciate if some one could atleast point out the resources for C++/CLR thread. C++/CLR Winform Threads. Would really appreciate it
Regards
Some errors are:
'printer1' uses undefined class 'MessagePrinter' 'Print' : is not a
member of 'System::Int32' 'System::Threading::ThreadStart' : a
delegate constructor expects 2 argument(s)
'System::Threading::Thread::Thread' : no appropriate default
constructor available 'System::Threading::Thread::Thread' : no
appropriate default constructor available 'syntax error : 'int' should
be preceded by ':' 'cannot declare a managed 'random' in an unmanaged
'MessagePrinter'may not declare a global or static variable, or a
member of a native type that refers to objects in the gc heap
'MessagePrinter::random' : you cannot embed an instance of a reference
type, 'System::Random', in a native type 'MessagePrinter::random' :
only static const integral data members can be initialized within a
class 'MessagePrinter' should be preceded by ':' 'void' should be
preceded by ':'

I fixed that code for you, but let me say one thing first: you really need to learn the basics first. This was not even C++/CLI code and you did not find or could not fix the most glaring syntax errors. Forget threads for a while, they are difficult. Learn basic stuff first.
#include "stdafx.h"
using namespace System;
using namespace System::Threading;
ref class MessagePrinter
{
private:
int sleepTime;
static Random^ random = gcnew Random();
// constructor to initialize a MessagePrinter object
public:
MessagePrinter()
{
// pick random sleep time between 0 and 5 seconds
sleepTime = random->Next( 5001 );
}
//controls Thread that prints message
void Print()
{
// obtain reference to currently executing thread
Thread^ current = Thread::CurrentThread;
// put thread to sleep for sleepTime amount of time
Console::WriteLine(current->Name + " going to sleep for " + sleepTime );
Thread::Sleep ( sleepTime );
// print thread name
Console::WriteLine( current->Name + " done sleeping" );
} // end method Print
}; // end class MessagePrinter
int main()
{
// Create and name each thread. Use MessagePrinter's
// Print method as argument to ThreadStart delegate.
MessagePrinter^ printer1 = gcnew MessagePrinter();
Thread^ thread1 = gcnew Thread(gcnew ThreadStart( printer1, &MessagePrinter::Print ) );
thread1->Name = "thread1";
MessagePrinter^ printer2 = gcnew MessagePrinter();
Thread^ thread2 = gcnew Thread ( gcnew ThreadStart( printer2, &MessagePrinter::Print ) );
thread2->Name = "thread2";
MessagePrinter^ printer3 = gcnew MessagePrinter();
Thread^ thread3 = gcnew Thread ( gcnew ThreadStart( printer3, &MessagePrinter::Print ) );
thread3->Name = "thread3";
Console::WriteLine( "Starting threads" );
// call each thread's Start method to place each
// thread in Started state
thread1->Start();
thread2->Start();
thread3->Start();
Console::WriteLine( "Threads started\n" );
Console::ReadLine();
return 0;
}

Be Aware that you leave the Main function and therefor all threads will be terminated... so place an Console.ReadLine() in the last line of your "main"...
Also: Your source code is C# and not C++/CLI...

Related

use a lambda to start a thread which is a class attribute

I would like to assign a name to a thread, the thread itself must do this. The thread is a class member of the class foo.
I would like to start this thread with a lambda but unfortunately I get the error message:
no match for call to '(std::thread) (foo::start()::<lambda()>)
Can someone explain to me where the problem is?
Previously I had created a temporary thread object, and put this with move on the thread "manage", however, I can then give no name.
class foo {
public:
int start()
{
this->manage([this](){
auto nto_errno = pthread_setname_np(manage.native_handle(),"manage"); // Give thread an human readable name (non portable!)
while(1){
printf("do work");
}
});
return 1;
}
private:
int retVal;
std::thread manage;
};
You passed the lambda in a wrong way, after initialization the manage thread can't be initialized again. you should create a new std::thread and assign it.
the following compiles and indeed prints "manage".
class foo {
public:
int start()
{
manage = std::thread([this]{
auto nto_errno = pthread_setname_np(manage.native_handle(),"manage");
char name[16];
pthread_getname_np(pthread_self(), &name[0], sizeof(name));
cout << name << endl;
});
manage.join();
return 1;
}
private:
int retVal;
std::thread manage;
};

how to pass structure to QT thread

Am trying to pass data structure to QT thread and but no success.
here is what am doing and have done.
i prepare data for the thread, like this and then tried to pass prepared data to thread before starting.
void mytable::prepare_data(){
// get table row count
int rowCount = ui->my_table_view->rowCount();
// create structure array based on rowCount
pnp_com_info pnp_data[rowCount];
/* pnp_com_info structure defined it top of file below includes to make it global
struct pnp_com_info{
QString com_name = "";
int x = 0;
int y = 0;
int angle = 0;
bool status = false;
};
*/
// loop on table rows columns and load pnp_data with data of columns
// PROBLEM : how to pass pnp_data structure to thread side ?
// can pass basic vars like
RunJobThread->mynum = 10;
// start QT thread
RunJobThread->start();
// std:: thread experiment
// std::stdthreadtest(pnp_data,rowCount);
}
run_job_thread.h source code
#ifndef RUN_JOB_THREAD_H
#define RUN_JOB_THREAD_H
#include <QObject>
#include <QThread>
class run_job_thread : public QThread
{
Q_OBJECT
public:
run_job_thread();
void run();
int mynum;
struct pnp_com_info_thread{
QString com_name = "";
int x = 0;
int y = 0;
int angle = 0;
bool status = false;
};
bool Stop; // bool to stop the job
signals:
void select_row_of_table_signal(int);
public slots:
};
#endif // RUN_JOB_THREAD_H
run_job_thread.cpp source code
#include "run_job_thread.h"
#include <QtCore>
run_job_thread::run_job_thread()
{
}
// run the thread
void run_job_thread::run(){
qDebug() << "my num passed value is : "<<this->mynum; // output : 10
// Goal : loop on pnp_data structure and emit signal to table rows
emit select_row_of_table_signal(5);
}
things i tried
instead of struct i tried to use other data containers like map, multimap, vectors but they give error , as am initializing pnp_com_info struct inside mytable::prepare_data() function based on rowCount which make it local and limited to prepare_data() function but with map,multimap,vector my plan was that they will be global and i will be able to access it from thread, however it not worked.
std::map<std::string, int,int,int> pnp_com_info; // error: too many template arguments for class template 'map'
std::multimap<std::string, int,int,int,bool> pnp_com_info; // error: too many template arguments for class template 'multimap'
std::vector<std::string, int,int,int,bool> pnp_com_info; // error: too many template arguments for class template 'vector'
i also tried std::thread which was partial success , i mean it was working ok but looks like std::thread not works with QT GUI thread as upon running app GUI will go freez although std::thread was doing its job
I would suggest to do the following, because the declaration of the
pnp_com_info pnp_data[rowCount];
is inside a context i think their lifecycle will be lost once you leave it, other problem is that it would be really "unsafe" to create this kind of arrays and then pass it from one side to another. Therefore I would create a QList and then pass either a copy or the reference to the worker thread. So
1) Create a QList pnp_data, in the public part of mytable
2) Fill all data using a for loop as follows.
3) Create another QList pnp_data or a QList *pnp_data (if you want to use a copy or a pointer)
4) Then just pass either a copy or a reference to the worker thread.
Then it should look like this:
mytable.h source code
public: QList<pnp_com_info> pnp_data;
mytable.cpp source code
void mytable::prepare_data(){
// get table row count
int rowCount = ui->my_table_view->rowCount();
// HERE YOU LOAD ALL THE VALUES TO THE LIST
for(int i = 0; i<rowCount; i++){
pnp_com_info itemToInsert;
//FILL HERE THE itemToInsert
//Insert the item inside the list.
pnp_data.append(itemToInsert);
}
// PROBLEM : how to pass pnp_data structure to thread side ?
// Either pass it as a copy
RunJobThread->pnp_data = pnp_data;
//or as a reference
QList<pnp_com_info> *pnpDataPointer = &pnp_data;
RunJobThread->pnp_data_reference = pnpDataPointer;
// start QT thread
RunJobThread->start();
// std:: thread experiment
// std::stdthreadtest(pnp_data,rowCount);
}
run_job_thread.h source code
#ifndef RUN_JOB_THREAD_H
#define RUN_JOB_THREAD_H
#include <QObject>
#include <QThread>
class run_job_thread : public QThread
{
Q_OBJECT
public:
run_job_thread();
void run();
struct pnp_com_info_thread{
QString com_name = "";
int x = 0;
int y = 0;
int angle = 0;
bool status = false;
};
QList<pnp_com_info> pnp_data; //This one if you create a copy
QList<pnp_com_info> *pnp_data_reference; //This if you want a pointer
bool Stop; // bool to stop the job
signals:
void select_row_of_table_signal(int);
public slots:
};
#endif // RUN_JOB_THREAD_H
I hope this helps.
First, don't subclass QThread to create a worker - re-read How To Really, Truly Use QThreads; The Full Explanation by Maya Posch. You will find it much more manageable to create a worker object and connect the threads started() to your worker's main method, and the worker's signals to the thread's quit() and deleteLater().
Then, it should be much more straightforward to pass your data to the worker before it's moved to the thread, or to use a signal connection if it needs to be passed when the worker is running (remember to register your structure with the meta-object system for that).

[C++, windows form]How do I make the main thread wait for the called thread to finish?

I created 2 buttons, one for start a new thread, the other to end it. The actual calculation inside the new thread involved new[] and delete[] so I don't abort the thread directly, but using a flag to end it. It may take some time to end the delete[] and result-saving, so I want the main thread to wait for the new thread to end. But however I tried, I find the new thread doesn't run(though its ThreadState is running) until the command lines for the stop-button are conducted. System::Threading::Thread works quite different from thread to me. Is it how it should be?
#include "stdafx.h"
ref class Form1 : System::Windows::Forms::Form
{
public:
//define a thread name and a flag to terminate the thread
System::Threading::Thread^ th1;
static bool ITP1=0;
Form1(void)
{InitializeComponent();}
System::Windows::Forms::Button^ ButtonStart;
System::Windows::Forms::Button^ ButtonStop;
System::Windows::Forms::Label^ Label1;
void InitializeComponent(void)
{
this->SuspendLayout();
this->ButtonStart = gcnew System::Windows::Forms::Button();
this->ButtonStart->Location = System::Drawing::Point(20, 20);
this->ButtonStart->Click += gcnew System::EventHandler(this, &Form1::ButtonStart_Click);
this->Controls->Add(this->ButtonStart);
this->ButtonStop = gcnew System::Windows::Forms::Button();
this->ButtonStop->Location = System::Drawing::Point(120, 20);
this->ButtonStop->Click += gcnew System::EventHandler(this, &Form1::ButtonStop_Click);
this->Controls->Add(this->ButtonStop);
this->Label1 = gcnew System::Windows::Forms::Label();
this->Label1->Location = System::Drawing::Point(20, 80);
this->Controls->Add(this->Label1);
this->ResumeLayout(false);
}
void ThreadStart()
{
for (int idx=0;idx<999999999;++idx)
{
if (ITP1) break;
}
this->Label1->Text = "finished";
ITP1=0;
}
System::Void ButtonStart_Click(System::Object^ sender, System::EventArgs^ e)
{
th1 = gcnew System::Threading::Thread(gcnew System::Threading::ThreadStart(this,&Form1::ThreadStart));
th1->Start();
this->Label1->Text = "running";
}
System::Void ButtonStop_Click(System::Object^ sender, System::EventArgs^ e)
{
if (th1->ThreadState==System::Threading::ThreadState::Running)
{
//use the flag to stop the thread
ITP1=1;
//the wait method using while+sleep doesn't work
while (th1->ThreadState==System::Threading::ThreadState::Running) System::Threading::Thread::Sleep(1000);
//replacing the wait method above with "th1->Join()" doesn't work either
}
}
};
int main()
{
Form1^ A1 = gcnew Form1();
A1->ShowDialog();
return 0;
}
You have to join() the called thread in the main thread. Then the main thread will wait until the called thread is finished.
See the documentation for Join to know how it is to be called.
Finally I found the cause. It's just the "this->" pointer in the new thread. Removing it makes everything OK.
I suppose it's because the Form allows operation on only one element at the same time. I ask the button-click to wait for the new thread, and the new thread tries to edit the other form element. They wait for each other to end and cause a dead loop.

Qt thread ID is equal to MainWindows? (moveToThread)

Now I want to create a thread and put in my class "AVC_file" inatance.
But when I print currentThreadId in textBroswer, I found MainWindows's threadID is same with the thread I created. show pitures like below.
Framework::Framework(QWidget * parent) : QMainWindow(parent)
{
ui.setupUi(this);
int threadID = (int)QThread::currentThreadId();
ui.textBrowser->append("Main Tread ID : " + QString::number(threadID));
}
void Framework::on_OpenAVCFile_clicked()
{
QString filePath = QFileDialog::getOpenFileName(
this, tr("Open File"), "C:\\", "AVC File (*.avc)"
);
if (!filePath.isEmpty())
{
QMessageBox::information(this, tr("File Name"), filePath);
}
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly))
{
QMessageBox::information(0, "info", file.errorString());
}
else {
QThread *thread = new QThread(this);
int threadID = (int)thread->currentThreadId();
ui.textBrowser->append("Second Tread ID : " + QString::number(threadID) + "\n");
AVC_File *AVC_file = new AVC_File();
AVC_file->moveToThread(thread);
connect(AVC_file, SIGNAL(requestFileContent(QString)), this, SLOT(addFileContent(QString)));
connect(AVC_file, SIGNAL(requestFileDebug(QString)), this, SLOT(addFileDebug(QString)));
connect(AVC_file, SIGNAL(requestFileCorrectness(bool, int)), this, SLOT(adddFileCorrectness(bool, int)));
connect(AVC_file, SIGNAL(requestNewValue(unsigned int, int)), this, SLOT(addNewValue(unsigned int, int)));
thread->start();
AVC_file->AVC_FileCheck(file);
}
}
Images about my code and results-->
Main Windows, create thread and results
Oh!I also try emit info in my "AVC_file" instance?like below.
void AVC_File::AVC_FileCheck(QFile &file)
{
int threadID = (int)QThread::currentThreadId();
emit requestFileContent("Thread ID by emit" + QString::number(threadID) + "\n");
QTextStream in(&file);
........
........
}
Emit threadID info
Anyone can help me?
BTW, I use visual studio Qt add-in to develop this project.
QThread::currentThreadId() is a static method.
When you call it, it returns the thread ID of the thread that executes it.
In both your cases that's the main thread.
There are several issues that I'll address in random order.
First of all, using thread IDs is bad user experience. Give the threads a descriptive name:
int main(...) {
QApplication app(...);
QThread myThread;
MyObject myObject;
myObject->moveToThread(&myThread);
QThread::currentThread()->setObjectName("mainThread");
myThread.setObjectName("myThread");
...
}
Then use QThread::currentThread()->objectName() to retrieve it. You can also pass QObject* to qDebug() to display the name of the thread:
qDebug() << QThread::currentThread();
Your signal invocation would then become:
QString currentThreadName() {
return QThread::currentThread()->objectName().isEmpty() ?
QStringLiteral("0x%1").arg(QThread::currentThread(), 0, 16) :
QThread::currentThread()->objectName();
}
...
emit requestFileContent(
QStringLiteral("Emitting from thread \"%1\"\n").arg(currentThreadName));
Then, use the above to deal with the thread you've created:
auto thread = new QThread(this);
thread->setObjectName("fileThread");
ui.textBrowser->append(QStringLiteral("Worker thread: \"%1\").arg(thread->objectName()));
auto AVC_file = new AVC_File;
AVC_file->moveToThread(thread);
...
But AVC_FileCheck is invoked from the main thread. Whether that's OK or not depends on how that method is implemented. It needs to be thread-safe, see this question for a discussion of that. TL;DR: The following pattern could be a starting point:
class AVC_file : public QObject {
Q_OBJECT
Q_SLOT void fileCheck_impl(QIODevice * dev) {
dev->setParent(this);
...
}
Q_SIGNAL void fileCheck_signal(QIODevice *);
public:
void fileCheck(QIODevice *dev) { fileCheck_signal(dev); }
AVC_file(QObject *parent = nullptr) : QObject(parent) {
connect(this, &AVC_file::fileCheck_signal, this, &AVC_file::fileCheck_impl);
...
}
};
Finally, your existing AVC_fileCheck API is broken. You pass QFile by reference: this won't ever work since it ceases to exist as soon as on_OpenAVCFile_clicked returns. When AVC_file uses that file in its thread, it's a dangling object reference.
Instead, you must pass the ownership of the file to AVC_file, and pass a pointer to an instance that AVC_file will dispose when done with. Or simply let AVC_file open the file for you!

Cocoa threads and class declaration connection

i'm not able to find answer in any stackoverflow topic. I have faced with Threads and Class, i want to use Class controller variables and actions, in global *.m file. without attached second Class.
here is code:
Controller.h
#import <Cocoa/Cocoa.h>
#interface Controller : NSObject
{
IBOutlet NSWindow *Main;
IBOutlet NSButton *myButton;
}
- (void)awakeFromNib;
- (IBAction)action:(id)sender;
- (IBAction)Display(id)sender;
#end
Controller.m
#import "Controller.h"
#implementation Controller
- (void)awakeFromNib
{
//At this point i can reach any variable from Controller.h
}
- (IBAction)Display:(id)sender
{
//Same, i can reach any variable from Controller.h
}
//After closing "}" and starting from new line, i can't call [Display] or anything else from Controller.h, my thread code goes here , and i want to write thread to call Display, or use awakeFromNib variables, strings, actions.
Thread code
#include assert.h
#include pthread.h
void* PosixThreadMainRoutine(void* data)
{
// I want to call here, example [Display click:self];
// but i only see [Controller]...
int ac = 0;
while (ac < 8)
{
sleep(1);
printf("Test");
ac++;
}
return NULL;
}
void LaunchThread()
{
// Create the thread using POSIX routines.
pthread_attr_t attr;
pthread_t posixThreadID;
int returnVal;
returnVal = pthread_attr_init(&attr);
assert(!returnVal);
returnVal = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
assert(!returnVal);
int threadError = pthread_create(&posixThreadID, &attr, &PosixThreadMainRoutine, NULL);
returnVal = pthread_attr_destroy(&attr);
assert(!returnVal);
if (threadError != 0)
{
// Report an error.
}
}
#end
Thread code works 100%, but i can't call any variable or function in PosixThreadMainRoutine, can some one explain how to do it?
`
If you want to execute code in separated thread with accesing to #interface methods/variables its better to use:
[NSThread detachNewThreadSelector:#selector(Display:) toTarget:self withObject:t];
or
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(10, queue, ^(size_t i) {
///Thread code here
});
In your example unclear - what is [Display click:self]; As I see Display - its method but not interface. Also PosixThreadMainRoutine() are not instance or class method. That is why you cant invoke call method. In general you dont have access because compiler dont know interface with name Dispaly and dont know declaration of click: method.
I sugest you next article: From C++ to Objective-C
Controller.m
I deleted thread, and i used this example:
[NSThread detachNewThreadSelector:#selector(Display:) toTarget:self withObject:nil];
- (IBAction)action:(id)sender{
[NSThread detachNewThreadSelector:#selector(Display:) toTarget:self withObject:nil];
}
It works like charm! i will save code , if someone knows answer i will try in currect situation.

Resources