Thursday, December 21, 2006
Portable thread library
Given how important multithreading programming has become, it is surprisingly difficult to find simple and usable portable C/C++ thead library.
In fact, this page claims there are only two such C++ libraries in existence: zthread and Boost.Threads.
zthread offers a clean, well-thought C++ design (claimed to be modeled after Java threads). Despite the fact that Cygwin was not mentioned as one of the supported platforms, it does compile and run under Cygwin with no visible (Cygwin-specific) problems. However,
- There is a complete absence of any examples, demos, unit tests, tutorials, etc. The only documentation provided is doxygen-generated.
- It appears that the implementation, rather than establishing a set of common wrappers over win32 and POSIX APIs (and perhaps others), is trying to more or less provide its own alternative implementation, perhaps having maximum platform-independence as one of the goals. As a result, library is quite volatile and does need a very active maintenance and user base, which does not seem to be there.
- As a typical example, some users report apparent problems under VC++ 6.0 which no one is able to diagnose or to comment on (thus one needs Visual .NET to use it).
- I spent long time trying to understand why my test program (under both Cygwin and Linux) was mysteriously crashing before I realized that zthread library is probably trying to do some very "intelligent" memory management, and as a result, all zthread-objects like mutex'es or threads must be dynamically allocated (via new); but then, you never need to release them...
So, is there a better alternative?
It appears that there is: it is POSIX Threads for Win32 project. They provide ready-to use libraries that can be (dynamically) linked with any Win32 application for (almost) complete POSIX thread support. See FAQ for long and interesting discussion on various ways to handle exceptions that arise from inside the library (in my experiments, I used pthreadVC1.lib)
Finally, a good pthread tutorial and documentation is available here.
Appendix. Sample C++ application implemented with zthread:
#include <string> #include <iostream> #include <zthread/Thread.h> #include <zthread/Mutex.h> ZThread::Mutex * output = new ZThread::Mutex (); class ThreadExample : public ZThread::Runnable { public: ThreadExample(std::string thread_name, size_t iterations) : name_(thread_name), num_times_to_loop_(iterations) {} void run() { for (size_t i = 0; i < num_times_to_loop_; i++) { output->acquire(); std::cerr << i << " " << name_ << "\n"; output->release(); } output->acquire(); std::cerr << name_ << " finished! " << std::endl; output->release(); } private: std::string name_; size_t num_times_to_loop_; }; int main() { using namespace std; using namespace ZThread; try { Thread t1(new ThreadExample("Thread-1", 50)); Thread t2(new ThreadExample("Thread-2", 50)); } catch (const Synchronization_Exception& e) { cerr << e.what() << "\n"; } }
and pthread:
#include <string> #include <iostream> #include <pthread.h> pthread_mutex_t output = PTHREAD_MUTEX_INITIALIZER; class ThreadExample { public: ThreadExample(std::string thread_name, size_t iterations) : name_(thread_name), num_times_to_loop_(iterations) {} void run() { for (size_t i = 0; i < num_times_to_loop_; i++) { pthread_mutex_lock (&output); std::cerr << i << " " << name_ << std::endl; pthread_mutex_unlock (&output); } pthread_mutex_lock (&output); std::cerr << name_ << " finished! " << std::endl; pthread_mutex_unlock (&output); } static void * prun(void * self) { ((ThreadExample *)self)->run(); return NULL; } private: std::string name_; size_t num_times_to_loop_; }; int main() { pthread_t p1, p2; pthread_create(&p1, NULL, ThreadExample::prun, new ThreadExample("Thread-1", 50)); pthread_create(&p2, NULL, ThreadExample::prun, new ThreadExample("Thread-2", 50)); pthread_exit(NULL); return 0; }
Labels: C, C++, multithreading, threads, windows