I have 2 Threads in a Qt5Application:
Thread A: contains a bunch of QObject derived class objects
Thread B: worker in this Thread has all the pointers to the objects in A
Thread A might be very busy at times and Thread B is only there to delegate Signals and manage some other stuff. It never writes to any of these objects, but I need to check some getter functions which return booleans from the objects in A.
in ThreadB:
if (objInThrA->isFinished()) { ... }
The isFinished() returns a boolean.
If Thread A is really busy in a function and I call these isFinished functions in Thread B, will my Thread B get stalled until Thread A is finished with its work, or will this work?
Qt signals and slots can be used between different threads. But there are two rules:
Last argument of connect() should be either Qt::QueuedConection or Qt::BlockingQueuedConnection (or defaults to Qt::AutoConnection, which is the same as Qt::QueuedConnection if objects belong to different threads). QueuedConnection means that emitter does not wait signal processing to be completed, BlockingQueuedConnection means it does.
QObject-derived classes are not suitable for passing between threads. They should be safely copied before that (see QMetaType docs).
You should never access members or directly call functions of an object which in another thread. The only safe way is to access them through signal/slot mechanism. You can have a signal in ThreadB and connect it to a slot in ThreadA which returns the value:
connect(objInThrB, SIGNAL(getFinished()), objInThrA, SLOT(isFinished()), Qt::BlockingQueuedConnection);
This way when you emit the signal in thread B like:
bool ret = getFinished();
the slot in thread A would be called when control returns to the event loop of thread A and the value would be returned. Thread B waits for the slot to be called, that's because the connection type is BlockingQueuedConnection. So be aware not to block the application main thread using this kind of blocking connection.
Ok, so I tested it myself.
In Thread B:
connect(this,SIGNAL(runWork()),objInThrA,SLOT(doWork()));
emit runWork();
QThread::sleep(2);
qDebug() << objInThrA->isFinished();
in Thread A:
qDebug() << "start A sleep";
QThread::sleep(10);
qDebug() << "end A sleep";
OUTPUT:
start A sleep
false
end A sleep
It works, however Im still unsure if I use it this way its correctly done and defined behavior.
The short answer is no.
When you run as described, you're directly calling methods from an object which is not in your thread (the object is in Thread A but you're calling one of its methods from Thread B). Directly calling a method is not something Qt has modified from standard C++, so it doesn't operate through signals, slots, or the event loop and is ignorant of your threading model. That means that if you call the method in Thread B, it runs in Thread B.
Calling methods on an object from another thread can be dangerous if you aren't careful about it because it introduces problems with concurrency. If Thread A is in the middle of updating the _mFinished data member when Thread B calls getFinished() on it, it may get a partially written value. In your specific example it happens to be that there is no "partially written" state for the boolean and you'll probably be fine.
Resolving concurrency problems is done through atomic operations on the elements which will be shared between multiple threads. Either you can use variables that are guaranteed to be atomic read and write operations, like booleans usually are, or you can use locking mechanisms to protect those variables. Mutexes and Semaphores are the most common locking mechanism and allow locking from multiple threads to limit access to the variables while they're being read and written. This is done in such a way as to avoid them being partially written with a new value when a read of the variable occurs.
I'd recommend reading up on mutexes and semaphores (generic multithreaded data structures) if you're doing work that involves more than one thread since they're critical to understanding threading in general. Additionally Qt has nice Qt wrapped versions of them that keep them simple to use and avoid some easy pitfalls in maintaining their usage (e.g. QMutexLocker).
Related
I want to do roughly this:
Initial thread:
write some values to global vars (they will never be written again)
This could be moderately large data (arrays, strings, etc). Cannot simply be made std::atomic<>.
spawn other threads
Other threads:
read the global state
do work, etc.
Now, I know I can pass arguments to std::thread, but I'm trying to understand the memory guarantees of C++ through this example.
Also, I am pretty confident that on any real-world implementation, creating a thread will cause a memory barrier ensuring that the thread can "see" everything the parent thread wrote up until that point.
But my question is: is this guaranteed by the standard?
Aside: I suppose I could add some dummy std::atomic<int> or so, and write to that before starting the other threads, then on the other threads, read that once on startup. I believe all the happens-before machinery would then guarantee that the previously-written global state is properly visible.
But my question is if something like that is technically required, or is thread creation enough?
Thread creation is enough. There is a synchronization point between the thread constructor and the start of the new thread per [thread.thread.constr]/6
Synchronization: The completion of the invocation of the constructor synchronizes with the beginning of the invocation of the copy of f.
This means that all state in the thread before the new thread is spawned is visible to the spawned thread.
So I'm trying to gracefully shut down several threads in loops when I interrupt a program (with SIGINT). Right now I use a callback that changes the state of a shared_ptr (which was copied to each thread) to indicate to all the other threads that it's time to break the loop (the threads check the state of the shared_ptr each iteration). This works, but I was wondering if it was "good" programming practice?
No, it is not guaranteed to be safe to modify a shared pointer in a signal handler. Nor is modification of a shared pointer safe (except copying which is safe despite modifying the internal state) across multiple threads
What would be safe is to use volatile std::sig_atomic_t as a flag and modify it in the signal handler. However, sig_atomic_t does not guarantee synchronisation to other threads than the one that handles the signal.
If you can rely on std::atomic<bool> being lock free (which isn't guaranteed by the standard), it would also be valid for modification in a signal handler, as well as guaranteeing thread synchronisation.
Otherwise, you could use a thread local volatile std::sig_atomic_t for the signal handler, and once change is detected in one thread, broadcast the information to other threads using a secondary thread syncronisation method (atomic, condition variable, etc.).
Another approach: you could have one thread simply waiting for the signal (no need for a sig-atomic flag), and once received, proceed with the thread synchronised broadcasting (same second phase as in previous suggestion). Note that the signal would have to be masked for other threads so that it is given for the waiting thread to handle. However, there is no good API for waiting for a signal in standard C++. There is sigwait in the POSIX standard, if you can rely on that.
Let class A is having only one object named as objectA and it's being on a separate thread (say "TCP"):
connect(&objectA, SIGNAL(MySignal()), &objectA, SLOT(MySlot()));
Note: I assume that Qt::AutoConnection will take care of whether it's QueuedConnection or DirectConnection. I am OK with any type, which makes it safer.
Now if B (say "Processor") & C (say "Utility") are different threads, which are invoking MySignal() with their own convenience.
In the MySlot(), some data of objectA is getting written.
Question:
Do I need mutex-locking to protect data of A a;?
OR
The MySignal() will be queued automatically and hence the MySlot() will get sequentially invoked?
Use case: Currently I am having a TCP thread which send/receive data to/from server. At times, 2 threads may send the data at same time. It's likely to run 2 threads in perfect parallel now a days due to multi-processor architecture.
If the object the slot is executed on is in a different thread than the object that does the emit, then the call is not sequential. The emit will not block. Thus if you access data that the emitting object might be writing to after the emit, you need to either synchronize that access with a mutex, or use a blocking connection (which means you're forcing sequential execution, meaning emit will block until the slot has returned.)
So, if the emit happens on a different thread, and you want it to block, use a blocking connection. If you don't want the emit to block, use a mutex to protect the data. If the emit happens on the same thread, it's going to be a blocking connection anyway.
However, if the emit happens in several threads, then you always need a mutex.
Assume those threads have been created on the main thread and since connect by default uses Qt::AutoConnection and docs say:
(Default) If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used. The connection type is determined when the signal is emitted.
By the time a thread emits a signal, since sender (the code running in QThread::run()) and receiver (the thread who has created the QThread object itself) are different threads, Qt::QueuedConnection is used. That is:
The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.
So all MySlot will be sequentially executed on the main thread.
Update
You've somewhat changed your question! In general, The following connection means: MySignal could be emitted in any threads (i.e. the thread in which you've called emit MySignal()), but MySlot is only called in the thread which objectA belongs to (i.e. thread affinity). If those threads are the same, the slot is executed synchronously.
connect(&objectA, SIGNAL(MySignal()), &objectA, SLOT(MySlot()));
Do I need mutex-locking to protect data of A a;?
In case you are accessing a's data outside of the thread in which a's event loop lives, yes you do need a lock.
There's something suspect in your design.
Normally, signals are protected, and emitted only from code running in that object's thread. A more conventional design would have objects B and C emit their own signals, and you would connect those signals to the slots of objectA.
Whilst what you have might work, it will be hard to reason about, and it's probably a good time to review your design before it becomes too tangled to understand what happens in which thread.
Does Qt provide a synchronization primitive that behaves in much the same way as Concurrency::event from Microsoft's Concurrency Runtime?
Specifically, I would like wait() in thread A to return even if it does not call wait() until after thread B has already called wakeAll(), but before a "reset" function is called. Also, I'd like something where reset() and set() do not have to be called from the same thread.
Basically, if I did not need to have async operations run in a specific thread (in my case it basically feeding tasks to an OpenGL rendering thread) QFuture and Qt Concurrent would be perfect.
If not specifically provided, is there a way to emulate that functionality with Qt?
Thanks!
I thought that I needed a QFuture a few times in the past as well, but always ended up using signals and slots to pass messages between the threads, carrying the data I would have put in the QFuture as an argument. Especially when there's a QEventLoop at the bottom of my thread.
Without an event loop I usually end up doing it manually with QWaitCondition, QMutex and QMutexLocker.
So sadly I would say that there isn't any higher-level class that would fit what you describe.
So now you have the mutex and the wait condition.
Simply add a boolean flag, which you access with the same mutex locked.
When you do wakeAll, also set flag to true. Before doing wait, check the flag first and don't wait it is true. And then reset is simply setting the flag to false.
I have a C++/Qt QThread worker thread, which stores its current status as an ENUM (e.g. values such as Working, Finished). Only the worker thread sets the ENUM.
I need to be able to read the status of the worker thread from another thread (the GUI thread), to display on the screen whether work is being done.
Is it safe to read/write the ENUM in one thread (worker), and read in other threads? Otherwise, should I use locking like QMutex in places where it is read/written?
As Neil said: Yes, you need locking. For your use case QReadWriteLock should be better suited than QMutex.
A more Qt-specific way to do this would be to have the worker thread emit a signal with its state whenever the state changes. Then the GUI would connect to the signal and update whatever it needs to for the state of the worker thread. If you do this, and pass the state by value, you shouldn't need any mutex protection of the state (since the value is copied when you emit the signal, that copy is never changed, and the copy is read in the UI thread). If you still need to query the thread for its state at different times, however, you'll still need locking.