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


    线程信号量和进程信号量类似,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 }

    测试结果:

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

  • 相关阅读:
    navigator
    历史记录跳转
    更改URL
    计数器
    窗口位置和大小
    open用法
    confirm用法
    项目中访问本地node服务跨域问题
    jenkins使用
    基于Vue的SSR
  • 原文地址:https://www.cnblogs.com/binchen-china/p/5471188.html
Copyright © 2020-2023  润新知