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,

Speaking of Boost.Threads, this is apparently just one piece of a huge collection of libraries - the latest release takes around 11M of source files - there is no documented way to build a single library separate from others.

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: , , , ,


Comments: Post a Comment



<< Home

This page is powered by Blogger. Isn't yours?