PDA

View Full Version : Globally accessible objects in threads



Cruz
20th June 2011, 22:38
Hello everyone!

I would like to find a nice solution to the following requirement. I need a globally accessible object, say an application wide Config. I use it in many places and preferably I would like to be able to access config variables anywhere in my code with config.variable. If it really really has to be, then I would accept the config->variable syntax implying that in this case Config is a pointer, which would bug me to no end because so far I made do without any pointers at all. Pointers are evil.

Anyhow, the real complication is that my application has two threads. The gui thread and a worker thread. In the gui thread the config can be changed and then the worker thread has to be updated with the changes in a thread safe way. And there are many objects living in the worker thread, all of which need to have access to the Config object.

So I'm asking you, how would you go about it?

stampede
20th June 2011, 22:48
In the gui thread the config can be changed and then the worker thread has to be updated with the changes in a thread safe way
Use signals & slots for this, they are thread safe. Let the config object emit a signal when it's changed.

And there are many objects living in the worker thread, all of which need to have access to the Config object.
If all you need is to notify the objects when config is changed, then your objects don't need to touch the config object. You can just send a signal with new configuration values to them.
Maybe this way you can save the config object from being exposed to other threads. Create and modify it only in main thread, and use signals & slots to notify other threads about new config options.

Cruz
20th June 2011, 23:01
Use signals & slots for this, they are thread safe.

Yes, preferably. But as I said, there are many objects in the worker thread and I would like to avoid connecting each of them individually.
It would be acceptable if all objects in the worker thread inherit from a "Configurable" and thus have their own instance of the config object.
But I don't know if there is a way to make the connections implicitly in the super class so that I don't have to bother making them explicitly
for every object I instantiate.

Santosh Reddy
20th June 2011, 23:03
You need to make all the members of you config struct / class as atomic in nature.

One of the simplest scenario is to have only integers (QAtomicInt) in config class, if you have complex data structures in config then you have no option, other than implementing you own thread-safe class using QMutex



Anyhow, the real complication is that my application has two threads. The gui thread and a worker thread. In the gui thread the config can be changed and then the worker thread has to be updated with the changes in a thread safe way. And there are many objects living in the worker thread, all of which need to have access to the Config object.
One possible solution to this scenario (if it fits you app), if your worker thread based on cycle / loop, where it can load the complete config structure into a thread local copy and then use it for rest of the loop / cycle, then load new copy of config next cycle (in thread-safe manner).

SixDegrees
20th June 2011, 23:35
In addition to the above, have a look at the QSettings object, which allows you to persist configuration changes across program runs. It already provides locking mechanisms.

stampede
21st June 2011, 00:19
It would be acceptable if all objects in the worker thread inherit from a "Configurable" and thus have their own instance of the config object.
I think you mean "have their own reference to the global config object", because having one config instance for every object makes it not very convenient to change the settings ;) (well, as long as those configs are not referencing the same shared data)

SixDegrees
21st June 2011, 07:54
So there's a main thread a a worker thread. Only the main thread can change config settings; the worker thread objects only read from it.

Thread safety is not an issue here. The main thread makes its changes, then tells the worker thread objects a change has occurred. Maybe you want some kind of lock so the main thread won't change any values while the worker objects update themselves, but that isn't clear. If you roll your own notification system, similar to Java's event registration, you don't even need that; the main thread simply waits until the call to update the workers returns before it does anything else. There's probably a similar mechanism available through Qt's signal/slot framework. But a vector of pointers to every worker object is all that's needed here.

Store references in it if you can't get over your irrational dislike of pointers. You'll still be using pointers, but the syntax will let you fool yourself into thinking you're not.

Cruz
21st June 2011, 14:01
I would like to avoid implementing thread safety with a locking mechanism, because my worker thread is fast steady paced (runs every 10 ms). So if the gui thread locks the config object to write updates into it, it might disrupt the steady pace of the worker thread, which is important to keep. But there is no problem transporting the config from the gui to the worker thread using signals and slots. The question is how to do it right on the other side. One config for all worker thread objects, or should they all have their individual copy. I'm sitll not sure how to do it best, there are so many options.


Store references in it if you can't get over your irrational dislike of pointers. You'll still be using pointers, but the syntax will let you fool yourself into thinking you're not.

I think references are safer because they are const and the object they point has to exist when they are assigned. There are more possibilities to do something wrong with pointers. Probably 90% of all runtime errors is a result of using pointers.

stampede
21st June 2011, 14:17
One config for all worker thread objects, or should they all have their individual copy.
Think about it, if all objects have different copies of config independent of each other, then how are you gonna change the config, without changing each local copy ? In that case you'll need to call threadObject->updateConfig(new_config) on every worker object, so this is not better than a signal & slot connection.
Only reason to have separate configs in each object I can think of, is that configs shares some underlying global config data, this way you can separate the thread-safety code to config class itself.

Cruz
21st June 2011, 14:29
Think about it, if all objects have different copies of config independent of each other, then how are you gonna change the config, without changing each local copy ? In that case you'll need to call threadObject->updateConfig(new_config) on every worker object, so this is not better than a signal & slot connection.

Yes, this is true. So let's say there is only one config object in the worker thread. Creating a reference or a pointer from all thread objects to the config is no less tedious than calling update on each of them or connecting every one of them to a signal. What happens if all worker thread objects are derived from ThreadObject that has a the config object as a static member? When a new config comes in from the gui through a slot, I only have to update the static config once and that should do it, right?

stampede
21st June 2011, 14:49
What happens if all worker thread objects are derived from ThreadObject that has a the config object as a static member? When a new config comes in from the gui through a slot, I only have to update the static config once and that should do it, right?
If thread objects are using shared data, then updating it once (in thread-safe way) will be enough.

Creating a reference or a pointer from all thread objects to the config is no less tedious than calling update on each of them or connecting every one of them to a signal.
In that case, just pick one schema and implement it, if you are satisfied with the results the great, if not, change the implementation :)

SixDegrees
21st June 2011, 15:45
I think references are safer because they are const and the object they point has to exist when they are assigned. There are more possibilities to do something wrong with pointers. Probably 90% of all runtime errors is a result of using pointers.

You can freely swap the words "reference" and "pointer" in these sentences and not change them in any meaningful way.

Cruz
21st June 2011, 15:53
You can freely swap the words "reference" and "pointer" in these sentences and not change them in any meaningful way.

Well not exactly, because you can always declare a pointer, have it point at a random memory location and try to access it, while with references you can't. But anyhow. It's best to avoid both.

stampede
21st June 2011, 15:55
I agree with SixDegrees, invalid references could be even more painful to debug, consider this:


#include <iostream>

class Test{
public:
int x;
};

int main( int argc, char ** argv ){
Test * test = new Test();
Test& ref = *test;
ref.x = 10;
std::cout << "value is " << ref.x;
delete test;
std::cout << "\nwhat now ? " << ref.x;
// test->x = 0; // this will cause crash on my machine, line above not
return 0;
}

on my machine it prints:


value is 10
what now ? 7409624

program runs without complains, while the "pointer" version nicely crashes. This is very simple example, but try to debug such errors with more complicated code. Not very pleasant experience.