线程信号量和进程信号量类似,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 }
测试结果:
结果和互斥锁效果一致,也可以配合条件变量使用!