|
|
Home » Community » Coffee corner » Thoughts about alternative approach to multithreading
|
Re: Thoughts about alternative approach to multithreading [message #19847 is a reply to message #19205] |
Tue, 27 January 2009 00:06 |
Mindtraveller
Messages: 917 Registered: August 2007 Location: Russia, Moscow rgn.
|
Experienced Contributor |
|
|
Finally I`ve finished some controller programming work and resumed developing of "alternative MT-approach" class.
Let`s summarize the idea. To avoid synchronization objects headache and possible synchronization issues it is proposed to make all the threads isolated from each other. It means that
* threads do not "see" each other`s variables (including global ones, the ones with atomic access and shared synchronization objects) - it fully conforms classic OOP approach.
* threads do not call other thread`s member functions directly
* the only possible threads interaction is made through sending some message into thread`s internal queue.
Generally this would make threads interactions far more predictable and debuggable.
After some thinking I`ve made a decision not to send messages but instead send requests to run thread public member function (callback). It was decided because "message" is actually a signal to do some job. So it is no need to create any artificial message identifiers while you directly request to execute these callbacks.
It looks like this:
class JobThread1 : public CallbackThread
{
public: //these members may be added into thread queue and must not be called directly
void Job11();
void Job12(const String &);
private: //all the realization details are private
//...
};
class class JobThread2 : public CallbackThread
{
public: //these members may be added into thread queue and must not be called directly
void Job21(const String &);
private: //all the realization details are private
//...
};
CONSOLE_APP_MAIN
{
JobThread1 jobs1;
JobThread2 jobs2;
for (int i=0; i<10; ++i)
{
jobs1.Add(&JobThread1::Job11);
jobs1.Add(&JobThread1::Job12, FormatInt(i));
jobs2.Add(&JobThread2::Job21, FormatIntHex(i));
}
};
You may even treat main thread as the same alt-MT thread. To do this you may have CallbackQueue variable and request it`s tasks. These tasks are processed with CallbackQueue::DoTasks().
Below is ready-to-use class with a simple test code.
If you are interested you may download and test it, or even use it in your apps. I hope more advanced versions of class will come soon (a number of optimizations is yet to be made).
"Alternative" MT requires a bit of reengineering threads processing functions. To make alt-MT program, you should think differently. Now you can`t share variables, now you don`t have a number of routines which are called in unpredictable sequence.
Instead you have messaging queues which mustn`t hold big number of messages (it is possible though not recommended). This means that thread must be logically solid as much as possible. This would keep all "tiny" interactions inside one thread.
Of course there are situations where "classic" MT with sync objects fits better. Situations include threads exchange with a huge number of tiny messages (inc/dec some variable). So if you cannot divide threads interaction into a (relatively small) number of (relatively medium) jobs - use "classic" MT.
I mean if you use more than 100`000 of messages per second - just use sync objects instead. But now you at least may choose to think "new way" on reorganizing threads member functions to make program stable or continue interacting with shared global variables to make it possibly quicker and less memory consuming but harder to debug and potentially less stable.
[Updated on: Tue, 27 January 2009 09:11] Report message to a moderator
|
|
|
Re: Thoughts about alternative approach to multithreading [message #22314 is a reply to message #19847] |
Fri, 03 July 2009 10:23 |
Mindtraveller
Messages: 917 Registered: August 2007 Location: Russia, Moscow rgn.
|
Experienced Contributor |
|
|
luzr wrote on Tue, 30 June 2009 00:15 | Well, I have some experiences now (did project based on queues, now planning to rewrite it to plain old locking) and I have something to say about the topic (IMO!):
Synchronization objects are simple to manage as compared to often complex race condition relations in queued systems.
|
What do mean exactly, could you please give a pair of examples why you switched back from queueing model? This is very important topic IMO.
I personally found them very comfortable and stable comparing to a tonns of mutexes.
[Updated on: Fri, 03 July 2009 10:24] Report message to a moderator
|
|
|
|
Re: Thoughts about alternative approach to multithreading [message #22339 is a reply to message #22326] |
Sun, 05 July 2009 21:43 |
Mindtraveller
Messages: 917 Registered: August 2007 Location: Russia, Moscow rgn.
|
Experienced Contributor |
|
|
luzr wrote on Fri, 03 July 2009 20:49 | I would like to, but right now I seem to be unable to describe it right. The problem was that it was user driven application and there are problems basically with "queue lag".
Maybe that the heart of problem is (was) the fact that it worked in "post" mode (not "execute") - messages (callbacks) being posted and not waiting for completition. Too often I ended with wrong events in the queue...
BTW, without posting, your method is equivalent to one mutex per instance and locking for any method call...
Mirek
|
1. What do you mean by "queue lag"? In my case case calling asynchronouse callback (this means: copy arguments, awake thread, post arguments and start execution), is almost as quick as calling U++ callback (I`ve posted these results above).
Personally I denied ANY types of events because I consider them absolutely artifical. The only thing which is really needed is executing some callback. So I had no problems identifying any types of events. I will appreciate any example where this approach fails (of course avoiding boundaries mentioned).
To be more precise, I takes more than single mutex per thread as there`s a queue and it really needs a semaphore.
|
|
|
Re: Thoughts about alternative approach to multithreading [message #22341 is a reply to message #22339] |
Sun, 05 July 2009 22:08 |
|
mirek
Messages: 13975 Registered: November 2005
|
Ultimate Member |
|
|
Mindtraveller wrote on Sun, 05 July 2009 15:43 |
luzr wrote on Fri, 03 July 2009 20:49 | I would like to, but right now I seem to be unable to describe it right. The problem was that it was user driven application and there are problems basically with "queue lag".
Maybe that the heart of problem is (was) the fact that it worked in "post" mode (not "execute") - messages (callbacks) being posted and not waiting for completition. Too often I ended with wrong events in the queue...
BTW, without posting, your method is equivalent to one mutex per instance and locking for any method call...
Mirek
|
1. What do you mean by "queue lag"? In my case case calling asynchronouse callback (this means: copy arguments, awake thread, post arguments and start execution), is almost as quick as calling U++ callback (I`ve posted these results above).
|
It is not about performance, but about race conditions.
Quote: |
Personally I denied ANY types of events because I consider them absolutely artifical. The only thing which is really needed is executing some callback. So I had no problems identifying any types of events. I will appreciate any example where this approach fails (of course avoiding boundaries mentioned).
|
Queued callbacks and events are equivalent here.
Well, I will try to describe the example. The code was image viewer. GUI thread to manage gui and other threads to do background loading.
Background threads do loading of whole directories in advance. Now the problem was that they got events to load directory, started performing it and meanwhile user switches to another directory.
With shared access (with mutex), this is quite easily manageable (I mean, stopping loading and doing something else). With queues, not so much.
Also, the fact that I need to pass all info using events is not very handy. With new U++ GUI threading, it is much easier to read actual GUI status in the background thread and adjust GUI as needed.
|
|
|
|
Re: Thoughts about alternative approach to multithreading [message #22410 is a reply to message #22341] |
Sat, 11 July 2009 16:06 |
Mindtraveller
Messages: 917 Registered: August 2007 Location: Russia, Moscow rgn.
|
Experienced Contributor |
|
|
Example you proposed sets a kind of problem. I spent some days thinking about it (I really met kind of this problem while programmed last project) and came to conclusion that each CallbackQueue/CallbackThread class should be descendant of CallbackNotifier class. Where CallbackNotifier is simply a Map<K,T> and a Mutex to synchronize access from multiple threads. This will enable asynchronouse messaging while thred's current queue callback is being executed. This is of course something from "classic" approach but anyway hides synchronization mutex.
In your example you will i.e. have to check this Map for current directory once per second. And if it is so, remove directory from Map and exit callback.
[Updated on: Sat, 11 July 2009 16:08] Report message to a moderator
|
|
|
|
Goto Forum:
Current Time: Thu Mar 28 14:06:18 CET 2024
Total time taken to generate the page: 0.01540 seconds
|
|
|