使用Linux平台上现有的信号量sem_t相关的一组API,可以方便地进行线程同步。现在用pthread_mutex_t和pthread_cond_t相关的一组API实现信号量机制。这组API包括:pthread_mutex_init,pthread_cond_init,pthread_mutex_lock,pthread_cond_signal,pthread_mutex_unlock,pthread_cond_wait,pthread_cond_timedwait,pthread_cond_destroy和pthread_mutex_destroy,可以在http://www.9linux.com找到各API的说明。下边,是封装的信号量类,以及测试代码。使用VS2005编辑,在虚拟机 Fedora 13中编译,测试通过。
MySemaphore.h
#ifndef Semaphore_Header #define Semaphore_Header #include <iostream> #include <pthread.h> #include <errno.h> #include <assert.h> using namespace std; //------------------------------------------------------------------------ class CSemaphoreImpl { protected: CSemaphoreImpl(int n, int max); ~CSemaphoreImpl(); void SetImpl(); void WaitImpl(); bool WaitImpl(long lMilliseconds); private: volatile int m_n; int m_max; pthread_mutex_t m_mutex; pthread_cond_t m_cond; }; inline void CSemaphoreImpl::SetImpl() { if (pthread_mutex_lock(&m_mutex)) cout<<"cannot signal semaphore (lock)"<<endl; if (m_n < m_max) { ++m_n; } else { pthread_mutex_unlock(&m_mutex); cout<<"cannot signal semaphore: count would exceed maximum"<<" m_n = "<<m_n<<"m_max = "<<m_max<<endl; } //重新开始等待m_cond的线程,可被调度 if (pthread_cond_signal(&m_cond)) { pthread_mutex_unlock(&m_mutex); cout<<"cannot signal semaphore"<<endl; } pthread_mutex_unlock(&m_mutex); } //------------------------------------------------------------------------ /* 信号量同步机制 信号量提供一个计数值,可以进行原子操作。V 将计数值加1,使得 等待该信号量的线程可以被调用(调用Set()),P 将计数值减1,使 当前线程被挂起,进行睡眠(调用Wait())。 当信号量的计数值被初始化为0时,调用P操作,将挂起当前线程。 当信号量被激活,即调用V操作后,被挂起的线程就有机会被重新调度了。 */ class CMySemaphore: private CSemaphoreImpl { public: /* 创建一个信号量,信号量计数值当前值为参数n,最大值为max。 如果只有n,则n必须大于0;如果同时有n和max,则n必须不小 于0,且不大于max */ CMySemaphore(int n); CMySemaphore(int n, int max); /* 销毁一个信号量 */ ~CMySemaphore(); /* 对信号量计数值做加1动作,信号量变为有信号状态,使得 另一个等待该信号量的线程可以被调度 */ void Set(); /* 对信号量计数值做减1动作,信号量变为无信号状态。若 计数值变得大于0时,信号量才会变为有信号状态。 */ void Wait(); /* 在给定的时间间隔里等待信号量变为有信号状态,若成功, 则将计数值减1,否则将发生超时。 */ void Wait(long lMilliseconds); /* 在给定的时间间隔里等待信号量变为有信号状态,若成功, 则将计数值减1,返回true;否则返回false。 */ bool TryWait(long lMilliseconds); private: CMySemaphore(); CMySemaphore(const CMySemaphore&); CMySemaphore& operator = (const CMySemaphore&); }; inline void CMySemaphore::Set() { SetImpl(); } inline void CMySemaphore::Wait() { WaitImpl(); } inline void CMySemaphore::Wait(long lMilliseconds) { if (!WaitImpl(lMilliseconds)) cout<<"time out"<<endl; } inline bool CMySemaphore::TryWait(long lMilliseconds) { return WaitImpl(lMilliseconds); } #endif
#include "MySemaphore.h" #include <sys/time.h> CSemaphoreImpl::CSemaphoreImpl(int n, int max): m_n(n), m_max(max) { assert (n >= 0 && max > 0 && n <= max); if (pthread_mutex_init(&m_mutex, NULL)) cout<<"cannot create semaphore (mutex)"<<endl; if (pthread_cond_init(&m_cond, NULL)) cout<<"cannot create semaphore (condition)"<<endl; } CSemaphoreImpl::~CSemaphoreImpl() { pthread_cond_destroy(&m_cond); pthread_mutex_destroy(&m_mutex); } void CSemaphoreImpl::WaitImpl() { if (pthread_mutex_lock(&m_mutex)) cout<<"wait for semaphore failed (lock)"<<endl; while (m_n < 1) { //对互斥体进行原子的解锁工作,然后等待状态信号 if (pthread_cond_wait(&m_cond, &m_mutex)) { pthread_mutex_unlock(&m_mutex); cout<<"wait for semaphore failed"<<endl; } } --m_n; pthread_mutex_unlock(&m_mutex); } bool CSemaphoreImpl::WaitImpl(long lMilliseconds) { int rc = 0; struct timespec abstime; struct timeval tv; gettimeofday(&tv, NULL); abstime.tv_sec = tv.tv_sec + lMilliseconds / 1000; abstime.tv_nsec = tv.tv_usec*1000 + (lMilliseconds % 1000)*1000000; if (abstime.tv_nsec >= 1000000000) { abstime.tv_nsec -= 1000000000; abstime.tv_sec++; } if (pthread_mutex_lock(&m_mutex) != 0) cout<<"wait for semaphore failed (lock)"<<endl; while (m_n < 1) { //自动释放互斥体并且等待m_cond状态,并且限制了最大的等待时间 if ((rc = pthread_cond_timedwait(&m_cond, &m_mutex, &abstime))) { if (rc == ETIMEDOUT) break; pthread_mutex_unlock(&m_mutex); cout<<"cannot wait for semaphore"<<endl; } } if (rc == 0) --m_n; pthread_mutex_unlock(&m_mutex); return rc == 0; } CMySemaphore::CMySemaphore(int n): CSemaphoreImpl(n, n) { } CMySemaphore::CMySemaphore(int n, int max): CSemaphoreImpl(n, max) { } CMySemaphore::~CMySemaphore() { }
// pthread_semaphore.cpp : 定义控制台应用程序的入口点。 // #include "MySemaphore.h" //创建一个信号量,其计数值当前值为0,最大值为3 CMySemaphore g_MySem(0, 3); //线程函数 void * StartThread(void *pParam) { //休眠1秒,确保主线程函数main中 //创建工作线程下一句g_MySem.Set();先执行 sleep(1); g_MySem.Wait(); //信号量计数值减1 cout<<"Do print StartThread"<<endl; return (void *)0; } int main(int argc, char* argv[]) { pthread_t thread; pthread_attr_t attr; assert ( !g_MySem.TryWait(10) ); g_MySem.Set(); //信号量计数值加1 g_MySem.Wait(); //信号量计数值减1 try { g_MySem.Wait(100); cout<<"must timeout"<<endl; //此处发生超时 } catch (...) { cout<<"wrong exception"<<endl; } g_MySem.Set(); g_MySem.Set(); assert ( g_MySem.TryWait(0) ); g_MySem.Wait(); assert ( !g_MySem.TryWait(10) ); //创建工作线程 pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE); if (pthread_create(&thread,&attr, StartThread,NULL) == -1) { cout<<"StartThread: create failed"<<endl; } g_MySem.Set(); //等待线程结束 void *result; pthread_join(thread,&result); assert ( !g_MySem.TryWait(10) ); //若将断言中的 ! 去掉,则会发生断言错误 //关闭线程句柄,释放资源 pthread_attr_destroy(&attr); int iWait; cin>>iWait; return 0; }
由此可见,信号量机制很关键的一点就是计数值 m_n。
原创作品,欢迎转载,麻烦带上链接:http://blog.csdn.net/chexlong/article/details/7098813 谢谢合作!