在使用线程时,经常要注意的就是访问临界资源加锁。

在编码过程由于粗心忘记加锁将带来不可预知的错误。这类错误单次运行或小并发时难以复现,当数据量变大,用户数增多时,轻则系统崩溃,大则引起数据错误。造成损失。

线程中互斥锁与进程的信号量类似,也可以看做是PV操作,用于保护临界资源,确保只有一个线程访问。

下面代码是不加锁错误代码,其中也涉及到之前提到的线程编程时需要注意的一些小细节。

  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 private:  
 34     pthread_mutex_t m_MutexLock;  
 35 };
 36 
 37 void MutexLockInterface::CreateMutexLock()
 38 {
 39     int ret = pthread_mutex_init(&m_MutexLock, NULL);
 40     if (0 != ret)
 41         cout<<"init mutex error!";
 42 }
 43 
 44 void MutexLockInterface::GetMutexLock()
 45 {
 46     pthread_mutex_lock(&m_MutexLock);
 47 }
 48 
 49 void MutexLockInterface::ReleaseMutexLock()
 50 {
 51     pthread_mutex_unlock(&m_MutexLock);
 52 }
 53 
 54 void MutexLockInterface::DestroyMutexLock()
 55 {
 56     pthread_mutex_destroy(&m_MutexLock);
 57 }
 58 
 59 
 60 class Service
 61 {
 62 public:
 63     static void* run(void *)    //类成员线程函数为static去除this指针
 64     {
 65         //m_MutexLock.GetMutexLock();
 66         if (0 == m_Tickets)
 67         {
 68             cout<<"stop operate!"<<endl;
 69         }
 70         else
 71         {
 72             cout<<"window2:we have "<<m_Tickets<<"Tickets"<<endl;
 73             sleep(1);
 74             --m_Tickets;
 75         }
 76         //m_MutexLock.ReleaseMutexLock();
 77     }
 78     int SetData(int data){m_Tickets = data;};
 79     int GetData(){return m_Tickets;};
 80     static int m_Tickets;
 81     static MutexLockInterface m_MutexLock;
 82 };
 83 int Service::m_Tickets = 1; //静态变量类外初始化
 84 MutexLockInterface Service::m_MutexLock;
 85 
 86 int main()
 87 {
 88     Service Srv;
 89     ThreadInterface Thread;
 90     Srv.m_MutexLock.CreateMutexLock();
 91     
 92     Thread.CreateThread(&Srv.run);
 93 
 94     //Srv.m_MutexLock.GetMutexLock();
 95     if (0 == Srv.GetData())
 96     {
 97         cout<<"stop operate!"<<endl;
 98     }
 99     else
100     {
101         cout<<"window1:we have "<<Srv.GetData()<<"Tickets"<<endl;
102         sleep(1);  //延时1s等待线程2
103         Srv.SetData(Srv.GetData() - 1);
104     }
105     //Srv.m_MutexLock.ReleaseMutexLock();
106     Thread.WaitThread();    //等待线程结束回收
107     cout<<Srv.GetData()<<endl;
108     return 0;
109 }

 

上述代码以售票为场景,当票只剩下一张时,两个窗口同时有人需要购票。

线程不加锁,执行结果如下:

很显然这不是我们想要的结果,只有一张票却卖出去了两张,最后余票显示为-1!

去除注释行,对临界资源操作是加锁,再运行程序,得到与预期一致的结果!

这就是线程互斥锁存在的原因。