I am using thread wrapper which checks if function which updates VCL (which also has some arguments) was called from main thread or not and then executes in within the context of Main thread always.
It works but I want to make it simpler. The problem is that I have to repeat this code in every function which needs VCL synchronization which is prone to errors. Is there a way to make this wrapper simpler and more re-useable? Note that this particular wrapper only uses one parameter but there can be any number of parameters which are copied to TLocalArgs and passed on.
Current code:
boost::scoped_ptr<TIdThreadComponent> WorkerThread;
...
void TForm1::SetMemoMessage(UnicodeString Msg)
{
// Check which thread called function, main thread or worker thread
if (GetCurrentThreadId() != System::MainThreadID)
{
struct TLocalArgs
{
TForm1 *Form;
UnicodeString Msg;
void __fastcall SetMemoMessage() // Same name as main function to make it easier to maintain
{
// We are in main thread now, safe to call message update directly
Form->SetMemoMessage(Msg);
}
};
// We are in worker thread, wrap into Synchronize
TLocalArgs Args = { this, Msg };
WorkerThread->Synchronize(&Args.SetMemoMessage);
return;
}
// MAIN THREAD CODE is very simple compared to wrapper above
Memo1->Text = Msg;
}
TThread::Synchronize() checks MainThreadID internally for you and calls the specified procedure directly if Synchronize() is called from the main thread. So just call Synchronize() unconditionally and let it handle the details. Synchronize() also has overloaded static versions available so you don't even need a TThread pointer to call it.
Try this:
void TForm1::SetMemoMessage(UnicodeString Msg)
{
struct TLocalArgs
{
UnicodeString Msg;
void __fastcall SetMemoMessage()
{
Form1->Memo1->Text = Msg;
}
};
TLocalArgs Args;
Args.Msg = Msg;
TThread::Synchronize(NULL, &Args.SetMemoMessage);
}
Related
I'm writing a DLL in C++Builder XE6 to communicate with a REST server. The DLL creates a TThread-derived thread to do GET requests in the background, using TIdHTTP. The DLL also exports functions to do GET and POST requests in the main thread, using a second TIdHTTP instance. Both TIdHTTP instances can trigger an OnAuthorization event if the server returns a 401 (Unauthorized) response code.
I've written a function to prompt the user for credentials, called PromptForCredentials(), which shows a standard Windows credentials dialog. This function is called if either instance triggers an OnAuthorization event (in the background thread via Synchronize()). Only thing is, the background thread can trigger an OnAuthorization event while the user is being prompted for credentials during an OnAuthorization event in the main thread and vice versa. This would show two copies of the credentials dialog at the same time.
I can use TCriticalSection to prevent calling PromptForCredentials() twice, so that only one copy of the credentials dialog is shown at a time. That way, if the main thread prompts for credentials, the background thread will block when it also tries to prompt for credentials and vice versa.
If authentication is successful in one thread, the other thread should use the same credentials instead of prompting the user a second time. I can do this by copying the Username and Password properties from one TIdHTTP instance to the other, either at the end of the OnAuthorization event or after the request is completed. However, if a second OnAuthorization event occurs during the first one, the user is still prompted twice for credentials. AFAIK, TCriticalSection doesn't provide a way to check if the lock is already acquired. Otherwise, I could wait until the lock is released and use the credentials without prompting a second time.
How do I prevent prompting the user for credentials twice in succession?
Update
The documentation for TMultiReadExclusiveWriteSynchronizer::BeginWrite() states:
As a rule, a thread should always discard previous samples from
protected memory after promoting a read lock to a write lock. However,
the calling thread can determine whether a state change has occurred
by examining return value of BeginWrite: True if the protected memory
has not been written to by another thread or False if another thread
may have modified the protected memory.
So, here's what I tried:
#include <System.SysUtils.hpp>
TMultiReadExclusiveWriteSynchronizer* Lock = NULL;
void GetCreds (const String Caption)
{
Lock->BeginRead();
try
{
// Retrieve globally stored credentials here.
bool Prompt = Lock->BeginWrite();
try
{
if (Prompt)
Application->MessageBox(_T("Prompt"), Caption.c_str(), MB_OK);
else
Application->MessageBox(_T("Use"), Caption.c_str(), MB_OK);
}
__finally
{
Lock->EndWrite();
}
}
__finally
{
Lock->EndRead();
}
}
class TMyThread : public TThread
{
typedef TThread inherited;
protected:
void __fastcall DoTask ();
virtual void __fastcall Execute ();
public:
__fastcall TMyThread () : inherited(true) {}
};
void __fastcall TMyThread::DoTask ()
{
GetCreds("Thread");
}
void __fastcall TMyThread::Execute ()
{
while (!Terminated)
{
Sleep(2000);
if (Terminated)
break;
Synchronize(DoTask);
}
}
void __fastcall TForm1::Button1Click (TObject *Sender)
{
Lock = new TMultiReadExclusiveWriteSynchronizer();
try
{
TMyThread* Thread = new TMyThread();
try
{
Thread->Start();
GetCreds("Main");
}
__finally
{
Thread->Terminate();
Thread->WaitFor();
delete Thread;
}
}
__finally
{
delete Lock;
}
}
When I click Button1, I get a message box with caption "Main" and text "Prompt". As expected, the user is prompted for credentials the first time.
With the message box still open, the background thread kicks in after 2 seconds with a (synchronized) call to GetCreds(). Since the main thread acquired a write lock, you would expect the background thread to be blocked on the BeginRead() call and no second message box to appear. However, I still get a second message box with caption "Thread" and text "Prompt".
To test, I switched from TMultiReadExclusiveWriteSynchronizer to TCriticalSection.
GetCreds() now looks like this:
void GetCreds (const String Caption)
{
Lock->Acquire();
try
{
Application->MessageBox(_T("Prompt"), Caption.c_str(), MB_OK);
}
__finally
{
Lock->Release();
}
}
I still get two message boxes, while I should only see the one from the main thread.
What am I doing wrong?
Update 2
As Remy pointed out, TCriticalSection locks are reentrant for the thread that has the lock. If I call GetCreds() directly in the thread, i.e. without Synchronize(), the code in my first update works as expected.
I also found that TCriticalSection has a TryEnter() method, whose return value can be used to check if another thread currently has the lock.
This is objectA which subclass QThread
void run()
{
while (continue)
emit query();
}
void work(int input, bool workdone)
{
// work hard here
if (workdone) { continue = false; }
}
This is some code in main object
{
ObjectA A* = new ObjectA(this);
connect(A, SIGNAL(query()), this, SLOT(handleQuery()));
objectA.start();
}
void handleQuery()
{
A.work(interger, allJobDONE);
}
OK, I don't know how to name the question. Basically, it is just "will this code work?" If yes, how would be the code sequence?
Let me explain my question. ObjectA is a thread. It is going to query information from time to time by emitting a query signal. When the query signal is grubbed by the main code, the main code decide whether there is job so as to send the job to ObjectA by calling work() function.
If this code works, both the run() and the work() function in the same object work at the same time. Is this possible?
There are few problems:
the function ObjectA::run() blocks the event loop of the thread;
A.work() is called from the wrong thread;
it is needed to think about proper deletion of A.
Instead of blocking while loop in run() it is better to use timer. However, in that case the thread event loop should be executed (that it done in the default implementation of QThread::run(). So some other member slot should be used for that task to start, for example:
void ObjectA::doLoop()
{
emit query();
QTimer::singleShot(0, this, SLOT(doLoop()));
}
That function should be called when the thread is started, for example it can be done by connection in ObjectA constructor:
connect(this, SIGNAL(started()), this, SLOT(doLoop()));
Even better to keep private pointer QTimer* to be able to stop that timer from work() or to have some other control. Note that in that case QTimer object should be in the same thread as ObjectA.
Normally the ObjectA::work() function should be triggerd by some signal from handleQuery(). The event loop of ObjectA will catch that signal and the work() will be started in ObjectA thread.
class Driver : Public QObject
{
Q_OBJECT
private:
// method command: sends a command
// signal ok: command executed, sends back a message
MyDevice *device;
public:
Deriver()
{
device = new MyDevice(0);
connect (mydevice,&MyDevice::ok,this,&Driver::onInitOk);
}
public slots:
void init()
{
device->command("init");
//at this point, I want to block this method until the device signals ok with a given msg
}
command()
{
device->command("setmode x");
device->command("cmd");
//at this point, I want to block this method until the device signals ok with a given msg
}
void onInitOk(QString msg)
{
//somehow unblock the actually running command, if the msg matches
}
}
I would like to use the command/init with a QueuedConnection, so they are executed async from the gui thread, and sequentially. (Am I right?)
How can I implement the blocking effectively?
Okay so I've edited based on the clarity of the comments given. The best place to look at would be the Qt Threading Guide. This can give a much better breakdown on the systems used for concurrency.
For your example I've added a QMutex object to your Driver class. It may be worth thinking about if you want to move the thread-based controls into the MyDevice class itself if you have access.
Driver()
{
moveToThread(new QThread());
device = new MyDevice(0);
}
void init()
{
mutex.lock();
const QString& result = device->command("init");
onInitOk(result);
}
void command()
{
mutex.lock();
device->command("setmode x");
const QString& result = device->command("cmd");
onInitOk(result);
}
void onInitOk(QString msg)
{
...[STUFF]
// Even when things go wrong you MUST unlock the mutex at some point.
// You can't keep the thread blocked forever in cases of poor results.
// As such it might be better practice to unlock in
// the same function that locks!
mutex.unlock();
}
QMutex mutex;
Bear in mind I am assuming you are wanting to access the functionality from the slots mechanism. Hence why we use the moveToThead() function. When the object is accessed via slots in the GUI thread it'll now run the function on a different thread.
Likewise the mutex only blocks for all the objects that share that one mutex instance. So depending on your implementation you may have to think about what is right for you in exposing that mutex.
I work in Qt and when I press the button GO I need to continuously send packages to the network and modify the interface with the information I receive.
The problem is that I have a while(1) in the button so the button never finishes so the interface is never updated. I thought to create a thread in the button and put the while(){} code there.
My question is how can I modify the interface from the thread? (For example how can I modify a textBox from the thread ?
Important thing about Qt is that you must work with Qt GUI only from GUI thread, that is main thread.
That's why the proper way to do this is to notify main thread from worker, and the code in main thread will actually update text box, progress bar or something else.
The best way to do this, I think, is use QThread instead of posix thread, and use Qt signals for communicating between threads. This will be your worker, a replacer of thread_func:
class WorkerThread : public QThread {
void run() {
while(1) {
// ... hard work
// Now want to notify main thread:
emit progressChanged("Some info");
}
}
// Define signal:
signals:
void progressChanged(QString info);
};
In your widget, define a slot with same prototype as signal in .h:
class MyWidget : public QWidget {
// Your gui code
// Define slot:
public slots:
void onProgressChanged(QString info);
};
In .cpp implement this function:
void MyWidget::onProgressChanged(QString info) {
// Processing code
textBox->setText("Latest info: " + info);
}
Now in that place where you want to spawn a thread (on button click):
void MyWidget::startWorkInAThread() {
// Create an instance of your woker
WorkerThread *workerThread = new WorkerThread;
// Connect our signal and slot
connect(workerThread, SIGNAL(progressChanged(QString)),
SLOT(onProgressChanged(QString)));
// Setup callback for cleanup when it finishes
connect(workerThread, SIGNAL(finished()),
workerThread, SLOT(deleteLater()));
// Run, Forest, run!
workerThread->start(); // This invokes WorkerThread::run in a new thread
}
After you connect signal and slot, emiting slot with emit progressChanged(...) in worker thread will send message to main thread and main thread will call the slot that is connected to that signal, onProgressChanged here.
P.s. I haven't tested the code yet so feel free to suggest an edit if I'm wrong somewhere
So the mechanism is that you cannot modify widgets from inside of a thread otherwise the application will crash with errors like:
QObject::connect: Cannot queue arguments of type 'QTextBlock'
(Make sure 'QTextBlock' is registered using qRegisterMetaType().)
QObject::connect: Cannot queue arguments of type 'QTextCursor'
(Make sure 'QTextCursor' is registered using qRegisterMetaType().)
Segmentation fault
To get around this, you need to encapsulate the threaded work in a class, like:
class RunThread:public QThread{
Q_OBJECT
public:
void run();
signals:
void resultReady(QString Input);
};
Where run() contains all the work you want to do.
In your parent class you will have a calling function generating data and a QT widget updating function:
class DevTab:public QWidget{
public:
void ThreadedRunCommand();
void DisplayData(QString Input);
...
}
Then to call into the thread you'll connect some slots, this
void DevTab::ThreadedRunCommand(){
RunThread *workerThread = new RunThread();
connect(workerThread, &RunThread::resultReady, this, &DevTab::UpdateScreen);
connect(workerThread, &RunThread::finished, workerThread, &QObject::deleteLater);
workerThread->start();
}
The connection function takes 4 parameters, parameter 1 is cause class, parameter 2 is signal within that class. Parameter 3 is class of callback function, parameter 4 is callback function within the class.
Then you'd have a function in your child thread to generate data:
void RunThread::run(){
QString Output="Hello world";
while(1){
emit resultReady(Output);
sleep(5);
}
}
Then you'd have a callback in your parent function to update the widget:
void DevTab::UpdateScreen(QString Input){
DevTab::OutputLogs->append(Input);
}
Then when you run it, the widget in the parent will update each time the emit macro is called in the thread. If the connect functions are configured properly, it will automatically take the parameter emitted, and stash it into the input parameter of your callback function.
How this works:
We initialise the class
We setup the slots to handle what happens with the thread finishes and what to do with the "returned" aka emitted data because we can't return data from a thread in the usual way
we then we run the thread with a ->start() call (which is hard coded into QThread), and QT looks for the hard coded name .run() memberfunction in the class
Each time the emit resultReady macro is called in the child thread, it's stashed the QString data into some shared data area stuck in limbo between threads
QT detects that resultReady has triggered and it signals your function, UpdateScreen(QString ) to accept the QString emitted from run() as an actual function parameter in the parent thread.
This repeats every time the emit keyword is triggered.
Essentially the connect() functions are an interface between the child and parent threads so that data can travel back and forth.
Note: resultReady() does not need to be defined. Think of it as like a macro existing within QT internals.
you can use invokeMethod() or Signals and slots mechanism ,Basically there are lot of examples like how to emit a signal and how to receive that in a SLOT .But ,InvokeMethod seems interesting .
Below is example ,where it shows How to change the text of a label from a thread:
//file1.cpp
QObject *obj = NULL; //global
QLabel *label = new QLabel("test");
obj = label; //Keep this as global and assign this once in constructor.
Next in your WorkerThread you can do as below:
//file2.cpp (ie.,thread)
extern QObject *obj;
void workerThread::run()
{
for(int i = 0; i<10 ;i++
{
QMetaObject::invokeMethod(obj, "setText",
Q_ARG(QString,QString::number(i)));
}
emit finished();
}
you start thread passing some pointer to thread function (in posix the thread function have the signature void* (thread_func)(void*), something equal under windows too) - and you are completely free to send the pointer to your own data (struct or something) and use this from the thread function (casting pointer to proper type). well, memory management should be though out (so you neither leak memory nor use already freed memory from the thread), but this is a different issue
I have a program which runs a thread. The thread performs processing all the time and it uses some synchronized queue.
The class snapshot is as follows:
public class MyClass:IDisposable
{
private Thread myThread = new Thread(threadFunc);
private volatile bool runThread = true;
public MyClass()
{
myThread.Start();
}
public Dispose()
{
runThread = false;
}
private void threadFunc()
{
try
{
while(runThread){
queue.Take(); //This method blocks the thread if queue is empty. It uses Monitor class
//do some processing
}
}
catch(Exception e){...}
}
private void otherFunc()
{
queue.enqueue(...);//this method is executed by main thread and uses lock while adding element to the queue.
}
}
When I call Dispose() method, the thread exists threadFunc() method, but after a sec I get an execption from this func "Unable to avaluate expression...", as if the tread was terminated while doing some work. Maybe it has just released from queue.Take() blocking and has no context to run. I know I'm missing something...
How can I solve such problem and terminate the thread from the Dispose method.
Many thanks!!!
Use the overload of Take that accepts a CancellationToken. You can get a reference to a token by using the CancellationTokenSource which also has the Cancel method that you can call from Dispose to unblock the Take method. You can read more cancellation here.
Use the poison pill approach: See this thread