线程同步(三)—— 信号量

线程信号量和进程信号量类似,Unix提供了两套与信号量有关的API。POSIX和System V。两套API都可以在线程和进程中使用。

进程中使用信号量是为了保证临界资源的控制,线程中已经有了互斥锁,而且还有条件变量对线程进行控制,信号量是不是就有点多余了呢?

其实在进程中也是可以使用互斥锁和控制变量,信号量和线程锁看似类似,但实际上还是有本质区别。

线程锁:只能对临界资源进行01操作,CPU在某个时刻只允许一个线程占用。谁加锁谁解锁。

信号量:PV操作,对结构体内计数器进行增减,允许多个线程进入临界资源,也没有限制必须同一个线程对信号量进行占用和释放。

            例如AB两个线程都在访问临界资源,C线程处于阻塞,只要AB任意释放,C即可获得信号量。

下面是与之前进程通信的SemOp类用于线程的代码。

  1 #include <pthread.h>  
  2 #include <unistd.h>  
  3 #include <sys/sem.h>
  4 #include <iostream>
  5 
  6 using namespace std;
  7 
  8 class ThreadInterface
  9 {
 10 public:
 11     void CreateThread(void* (*func)(void *),void *sem);
 12     void WaitThread();
 13 private:
 14     pthread_t m_pTread;   
 15 };
 16 
 17 void ThreadInterface::CreateThread(void* (*func)(void *),void *sem)
 18 {
 19     pthread_create(&m_pTread, NULL, func, sem); 
 20 }
 21 
 22 void ThreadInterface::WaitThread()
 23 {
 24     pthread_join(m_pTread, NULL); 
 25 }
 26 
 27 class SemOp
 28 {
 29 public:
 30     SemOp():m_iSemID(0){};
 31     void InitSem();
 32     void GetSem();
 33     void ReleaseSem();
 34     void DelSem();
 35 private:
 36     int m_iSemID;
 37 };
 38 
 39 void SemOp::InitSem()
 40 {
 41     if ((m_iSemID = semget(IPC_PRIVATE, 1, 0600|IPC_CREAT)) <= 0)
 42         cout<<"get semID failure!"<<endl;
 43     semctl(m_iSemID, 0, SETVAL, 1);
 44 }
 45 
 46 void SemOp::GetSem()
 47 {
 48     struct sembuf sem_get;
 49     sem_get.sem_num = 0;
 50     sem_get.sem_op = -1;
 51     sem_get.sem_flg = SEM_UNDO;
 52     semop(m_iSemID,&sem_get,1);
 53 }
 54 
 55 void SemOp::ReleaseSem()
 56 {
 57     struct sembuf sem_release;
 58     sem_release.sem_num = 0;
 59     sem_release.sem_op = 1;
 60     sem_release.sem_flg = SEM_UNDO;
 61     semop(m_iSemID,&sem_release,1);
 62 }
 63 
 64 void SemOp::DelSem()
 65 {
 66     semctl(m_iSemID, 0, IPC_RMID);
 67 }
 68 
 69 class Service
 70 {
 71 public:
 72     static void* run(void *pSem)
 73     {
 74         SemOp *sem = reinterpret_cast<SemOp*>(pSem);//指针强转
 75         sem->GetSem();
 76         for (int i = 0; i < 5; ++i)
 77         {
 78             cout<<"This is thread 2!"<<endl;
 79             sleep(1);
 80         }
 81         sem->ReleaseSem();
 82     }
 83 };
 84 
 85 int main()
 86 {
 87     Service Srv;
 88     ThreadInterface Thread;
 89     SemOp sem;
 90     
 91     sem.InitSem();
 92     Thread.CreateThread(&Srv.run, &sem);    //向线程传入信号量
 93     
 94     sem.GetSem();
 95     for (int i = 0; i < 5; ++i)
 96     {
 97         cout<<"This is thread 1!"<<endl;
 98         sleep(1);
 99     }
100     sem.ReleaseSem();
101     Thread.WaitThread();
102     sem.DelSem();
103     return 0;
104 }

测试结果:

结果和互斥锁效果一致,也可以配合条件变量使用!

原文地址:https://www.cnblogs.com/binchen-china/p/5471188.html