• 线程同步(二)—— 条件变量


    上篇提到线程针对临界值操作时需要加锁,但是线程访问临界资源只通过锁来控制是不够的。

    比如对一个数据进行操作,A线程需要读,B线程进行写。

    A线程先访问临界资源,发现没有数据可以读,只能等待B线程先写,此时又占用了互斥锁,导致B线程无法得到锁,进行写操作。

    此时就需要用到条件变量了,条件变量的目的就是控制线程的先后执行,保证临界资源的有效性。

    下面依然是售票的一个场景,此时一个线程售票,一个线程退票。

      1 #include <pthread.h>  
      2 #include <unistd.h>  
      3 #include <iostream>
      4 
      5 using namespace std;
      6 
      7 class ThreadInterface
      8 {
      9 public:
     10     void CreateThread(void* (*func)(void *));
     11     void WaitThread();
     12 private:
     13     pthread_t m_pTread;   
     14 };
     15 
     16 void ThreadInterface::CreateThread(void* (*func)(void *))
     17 {
     18     pthread_create(&m_pTread, NULL, func, NULL); 
     19 }
     20 
     21 void ThreadInterface::WaitThread()
     22 {
     23     pthread_join(m_pTread, NULL); 
     24 }
     25 
     26 class MutexLockInterface
     27 {
     28 public:
     29     void CreateMutexLock();
     30     void GetMutexLock();
     31     void ReleaseMutexLock();
     32     void DestroyMutexLock();  
     33     pthread_mutex_t m_MutexLock;  
     34 };
     35 
     36 void MutexLockInterface::CreateMutexLock()
     37 {
     38     int ret = pthread_mutex_init(&m_MutexLock, NULL);
     39     if (0 != ret)
     40         cout<<"init mutex error!";
     41 }
     42 
     43 void MutexLockInterface::GetMutexLock()
     44 {
     45     pthread_mutex_lock(&m_MutexLock);
     46 }
     47 
     48 void MutexLockInterface::ReleaseMutexLock()
     49 {
     50     pthread_mutex_unlock(&m_MutexLock);
     51 }
     52 
     53 void MutexLockInterface::DestroyMutexLock()
     54 {
     55     pthread_mutex_destroy(&m_MutexLock);
     56 }
     57 
     58 class CondInterface
     59 {
     60 public:
     61     void CreateCond();
     62     void WaitCond(pthread_mutex_t *mutex);
     63     void WakeupCond();
     64     void DestroyCond();
     65 private:
     66     pthread_cond_t m_Cond;
     67 };
     68 
     69 void CondInterface::CreateCond()
     70 {
     71     int ret = pthread_cond_init(&m_Cond, NULL);
     72     if (0 != ret)
     73         cout<<"init mutex error!";
     74 }
     75 void CondInterface::WaitCond(pthread_mutex_t *mutex)
     76 {
     77     pthread_cond_wait(&m_Cond, mutex);
     78 }
     79 void CondInterface::WakeupCond()
     80 {
     81     pthread_cond_broadcast(&m_Cond);
     82 }
     83 void CondInterface::DestroyCond()
     84 {
     85     pthread_cond_destroy(&m_Cond);
     86 }
     87 
     88 class Service
     89 {
     90 public:
     91     static void* run(void *)
     92     {
     93         m_MutexLock.GetMutexLock();
     94         cout<<"we have "<<m_Tickets<<"Tickets"<<endl;
     95         sleep(1);
     96         m_Tickets++;
     97         //Cond.WakeupCond();
     98         m_MutexLock.ReleaseMutexLock();
     99     }
    100     int SetData(int data){m_Tickets = data;};
    101     int GetData(){return m_Tickets;};
    102     static int m_Tickets;
    103     static MutexLockInterface m_MutexLock;
    104     static CondInterface Cond;
    105 };
    106 int Service::m_Tickets = 0;
    107 MutexLockInterface Service::m_MutexLock;
    108 CondInterface Service::Cond;
    109 
    110 int main()
    111 {
    112     Service Srv;
    113     ThreadInterface Thread;
    114     Srv.m_MutexLock.CreateMutexLock();
    115     Srv.Cond.CreateCond();
    116     Thread.CreateThread(&Srv.run);
    117 
    118     Srv.m_MutexLock.GetMutexLock();
    119     if (0 == Srv.GetData())
    120     {
    121         //Srv.Cond.WaitCond(&Srv.m_MutexLock.m_MutexLock);
    122         cout<<"wait!"<<endl;
    123     }
    124     
    125     cout<<"window1:we have "<<Srv.GetData()<<"Tickets"<<endl;
    126     sleep(1);
    127     Srv.SetData(Srv.GetData() - 1);
    128         
    129     Srv.m_MutexLock.ReleaseMutexLock();
    130     Thread.WaitThread();
    131     cout<<Srv.GetData()<<endl;
    132     return 0;
    133 }

    不使用条件变量执行结果如下:

    线程1先执行,此时并没有票。此时应该先放弃锁,让线程2先执行,取消注释执行结果如下:

    由此可以看出,条件变量让线程1暂时先放弃锁进入阻塞,等线程2执行完毕后,唤醒线程1。再进行正确操作。

  • 相关阅读:
    Overloaded的方法是否可以改变返回值的类型
    parseXXX的用法
    java的类型转换问题。int a = 123456;short b = (short)a;System.out.println(b);为什么结果是-7616?
    UVA 10405 Longest Common Subsequence(简单DP)
    POJ 1001 Exponentiation(大数处理)
    POJ 2318 TOYS(计算几何)(二分)
    POJ 1265 Area (计算几何)(Pick定理)
    POJ 3371 Flesch Reading Ease (模拟题)
    POJ 3687 Labeling Balls(拓扑序列)
    POJ 1094 Sorting It All Out(拓扑序列)
  • 原文地址:https://www.cnblogs.com/binchen-china/p/5453216.html
Copyright © 2020-2023  润新知