[Boost.thread] Simultaneously starting thread execution

Hi there, I'm trying to find a way to let a number of threads start execution simultaneously, and in any case not before a certain condition has come true. I would also like to terminate them within a relatively short time frame. I can not use the Boost.Thread barrier class, as I do not know the number of threads in advance (users register consumer-type objects, and I do not know how many there will be). I also believe I do not have to use a condition variable, as the different threads need to synchronize their access to a data ressource anyway, and I can use the same mutex to block them in the beginning. I have thus come up with something like the code quoted below. Are there easier ways to do this with the Boost.Thread library ? One of the problems (which seems to be unrelated to the code below) is that the three threads do not get called equally often. In one run, one thread was called 14564 times, another 1607 times and the third one 8676 times. Thanks and Best Regards, Ruediger /***********************************************************************/ #include <iostream> #include <boost/cstdint.hpp> #include <boost/bind.hpp> #include <boost/thread/mutex.hpp> #include <boost/thread/condition.hpp> #include <boost/thread/condition_variable.hpp> #include <boost/thread/thread.hpp> using namespace std; class test { public: test() :lock(helloMutex_), jointData_(0), MAXJOINTDATA(10000), thread1(boost::bind(&test::sayHello, this)), thread2(boost::bind(&test::sayHello, this)), thread3(boost::bind(&test::sayHello, this)) { /* nothing */ } void startAndStopThreads(){ lock.unlock(); while(true){ boost::unique_lock<boost::mutex> local_lock(helloMutex_); if(jointData_ >= MAXJOINTDATA){ thread1.interrupt(); thread2.interrupt(); thread3.interrupt(); break; } } thread1.join(); thread2.join(); thread3.join(); } void sayHello(){ for(;;){ if(boost::this_thread::interruption_requested()) break; boost::unique_lock<boost::mutex> local_lock(helloMutex_); std::cout << "Hello world Nr. " << jointData_++ << " from thread " << boost::this_thread::get_id() << std::endl; } } private: boost::mutex helloMutex_; boost::unique_lock<boost::mutex> lock; uint32_t jointData_; const uint32_t MAXJOINTDATA; boost::thread thread1, thread2, thread3; }; main(){ test Test; Test.startAndStopThreads(); std::cout << "Done ..." << std::endl; }

On Wed, Aug 06, 2008 at 01:36:19AM +0200, Ruediger Berlich wrote:
I'm trying to find a way to let a number of threads start execution simultaneously, and in any case not before a certain condition has come true.
Define "simultaneously". If you have more threads than CPUs, it should be obvious that, due to time-slicing, it is physically impossible that they start simultaneously. Even with more CPUs than threads, this is achievable only in architecture-specific way and with instructions that are accessible only to supervisor-level code (e.g. Pentium's MONITOR instruction or broadcasted interprocessor interrupt -- if the latter exists at all). Every other mechanism will incur some delay between start of different threads.
I also believe I do not have to use a condition variable, as the different threads need to synchronize their access to a data ressource anyway, and I can use the same mutex to block them in the beginning.
While one thread is in the critical section protected by the mutex, all others will wait until that thread exits the critical section. This is hardly "simultaneous" start.
One of the problems (which seems to be unrelated to the code below) is that the three threads do not get called equally often. In one run, one thread was called 14564 times, another 1607 times and the third one 8676 times.
This is perfectly normal, and is not a "problem". Threaded code that depends on relative speeds of threads (on a general-purpose OS) is calling for trouble. Can you describe what are you trying to achieve? Threads might not be the best solution..

Hi there, o.k., being a physicist, I hope I can find the right words in this computer-scientist-rich environment ;-) Imagine an environment where m entities produce items ("producers") which are processed by n workers ("consumers"), running as threads. The results are then returned back to the original entities, which themselves run in threads. Both m and n are not known in advance, as it is the user (or an automated procedure) that determines how many producers and consumers there will be. In the middle of this sits a broker, which takes care of all communication between producers and consumers. Both need to register with the broker before being able to communicate with each other. I want to have as few restrictions for my users as possible, as I want my library to be easy to use. Hence there is no rule when producers and consumers may or may not be registered. However, my current setup makes it desirable that consumer threads do not *start* before at least one producer has been registered (they are started by the broker). Hence I need to have a mechanism that blocks all consumers that have been registered before the first producer, until such time that the first items to be processed are available. If the number of consumer threads would be known in advance, Boost's Thread-Barrier might be a possible choice. As I do not know this number, however, I'll probably have to do my own locking (see my sample implementation). Best, Ruediger Zeljko Vrba wrote:
On Wed, Aug 06, 2008 at 01:36:19AM +0200, Ruediger Berlich wrote:
I'm trying to find a way to let a number of threads start execution simultaneously, and in any case not before a certain condition has come true.
Define "simultaneously". If you have more threads than CPUs, it should be obvious that, due to time-slicing, it is physically impossible that they start simultaneously. Even with more CPUs than threads, this is achievable only in architecture-specific way and with instructions that are accessible only to supervisor-level code (e.g. Pentium's MONITOR instruction or broadcasted interprocessor interrupt -- if the latter exists at all). Every other mechanism will incur some delay between start of different threads.
I also believe I do not have to use a condition variable, as the different threads need to synchronize their access to a data ressource anyway, and I can use the same mutex to block them in the beginning.
While one thread is in the critical section protected by the mutex, all others will wait until that thread exits the critical section. This is hardly "simultaneous" start.
One of the problems (which seems to be unrelated to the code below) is that the three threads do not get called equally often. In one run, one thread was called 14564 times, another 1607 times and the third one 8676 times.
This is perfectly normal, and is not a "problem". Threaded code that depends on relative speeds of threads (on a general-purpose OS) is calling for trouble.
Can you describe what are you trying to achieve? Threads might not be the best solution..
-- Kind Regards / Mit freundlichen Gruessen, Ruediger Berlich ------------------------------------------------------------------------ Dr. Ruediger Berlich | E-mail: ruediger.berlich@iwr.fzk.de Forschungszentrum Karlsruhe | Web: http://ruediger.berlich.com Steinbuch Centre for Computing | Phone: +49 (0)7247 825678 Hermann-von-Helmholtz-Platz 1 | Fax: +49 (0)7247 824972 D-76344 Eggenstein-Leopoldshafen | Mobile: +49 (0)178 5567842 ------------------------------------------------------------------------ /*************************************************************************/ The Steinbuch Centre for Computing of Karlsruhe Institute of Technology (the Cooperation of Forschungszentrum Karlsruhe GmbH and Universitaet Karlsruhe TH) will run its annual GridKa School from September 8th to 12th, 2008. Please find further information at http://www.fzk.de/gks08 . /*************************************************************************/ Forschungszentrum Karlsruhe GmbH Sitz: Weberstraße 5 76133 Karlsruhe Amtsgericht Mannheim HRB 100302 Vorsitzende des Aufsichtsrats: Baerbel Brumme-Bothe Vors. der Geschäftsführung: Prof. Dr. Eberhard Umbach

Ruediger Berlich: ...
If the number of consumer threads would be known in advance, Boost's Thread-Barrier might be a possible choice. As I do not know this number, however, I'll probably have to do my own locking (see my sample implementation).
You might want to look at Phasers: http://www.infoq.com/news/2008/07/phasers http://www.cs.rice.edu/%7Evs3/PDF/SPSS08-phasers.pdf

I wrote the following to do some volume testing on a service, may help you: boost::mutex mutex; bool testthreads( std::string& mdoid, std::vector<unsigned char>& userpin ) { boost::mutex::scoped_lock lock( mutex );//wait for the main thread to say go lock.unlock();//release mutex immediately to allow other threads to start performOp(); return true; } bool testmultithreaded() { printf( "Please enter thread count [1-2048] : " ); std::string input; std::cin >> input; unsigned long encCnt = std::strtoul( input.c_str(), NULL, 0 ); if( encCnt == 0 || encCnt > 2048 ) { printf( "Thread count out of range" ); return false; } const int threadCnt = encCnt; std::vector<boost::shared_ptr<boost::thread>> threads; boost::timer t; boost::mutex::scoped_lock lock( mutex );//lock the mutex to stop threads from starting for( int i = 0; i < threadCnt; ++i ) { threads.push_back( boost::shared_ptr<boost::thread>( new boost::thread ( boost::bind( &testthreads, mdoid, userpin ) ) ) ); } double threadscreated = t.elapsed(); lock.unlock();//start the threads off for( int i = 0; i < threadCnt; ++i ) { threads[i]->join();//wait for each thread to finish } double threadsFinished = t.elapsed(); boost::mutex::scoped_lock hmilock(hmiMutex); printf( "%lu threads completed\n", encCnt ); printf( "Threads created in %f seconds\n", threadscreated ); printf( "Threads completed in %f seconds\n", threadsFinished - threadscreated ); return true; } ****************************************************************************** "This message and any attachments are solely for the intended recipient and may contain confidential and privileged information. If you are not the intended recipient, any disclosure, copying, use, or distribution of the information included in this message and any attachments is prohibited. If you have received this communication in error, please notify us by reply e-mail and immediately and permanently delete this message and any attachments. Thank you." Interactive Transaction Solutions Ltd (2473364 England) Registered Office: Systems House, Station Approach Emsworth PO10 7PW ********************************************************************** Ce message �lectronique contient des informations confidentielles � l'usage unique des destinataires indiqu�s, personnes physiques ou morales. Si vous n'�tes pas le destinataire voulu, toute divulgation, copie, ou diffusion ou toute autre utilisation de ces informations, est interdite. Si vous avez re�u ce message �lectronique par erreur, nous vous remercions d'en avertir son exp�diteur imm�diatement par email et de d�truire ce message ainsi que les �l�ments attach�s. Interactive transaction Solutions SAS- France (RCS Pontoise : 489 397 877) Si�ge social : Parc Saint Christophe, 10, Avenue de l�Entreprise 95865 Cergy-Pontoise Cedex ______________________________________________________________________ This email has been scanned by the MessageLabs Email Security System. For more information please visit http://www.messagelabs.com/email ______________________________________________________________________

Le Mer 6 août 2008 16:45, Patrick Loney a écrit :
I wrote the following to do some volume testing on a service <snip>
How would go and adapt this if we wanted the thread to return into a waiting state after performing an operation so I can reuse them later for another cyle of operations triggered from the 1st thread ?

On Wed, Aug 06, 2008 at 10:53:43AM +0200, Ruediger Berlich wrote:
will be. In the middle of this sits a broker, which takes care of all communication between producers and consumers. Both need to register with the broker before being able to communicate with each other.
Having a single broker for all communication between producers and consumers defeats the point of having threads. Eventually, the broker will become the bottleneck (serialization point). Or did I misunderstand the first sentence?
has been registered (they are started by the broker). Hence I need to have a mechanism that blocks all consumers that have been registered before the first producer, until such time that the first items to be processed are available.
Condition variable?

Hi Zeljko,
will be. In the middle of this sits a broker, which takes care of all communication between producers and consumers. Both need to register with the broker before being able to communicate with each other.
Having a single broker for all communication between producers and consumers defeats the point of having threads. Eventually, the broker will become the bottleneck (serialization point). Or did I misunderstand the first sentence?
The part that is indeed serialized this way is the match-making between consumer and producer. Match-making just means fetching the next available producer from a list and connecting it to the consumer. Once that has happened, the match-maker (aka Broker) is free for a new connection. Processing the data takes far longer than the match-making. And what's handed over between producer and consumer in the end is just a shared_ptr (because sometimes a producer might go away and I can't hand back the data. So I don't want a headache with freeing the memory). So most part of the compute time will still be spent concurrently. I have thought of ways of handling even the hand-over concurrently, but I'm not sure they are worth the effort. The data processing time is far too long in comparison to the hand-over. Best, Ruediger
participants (5)
-
joel falcou
-
Patrick Loney
-
Peter Dimov
-
Ruediger Berlich
-
Zeljko Vrba