• 线程同步(一)—— 互斥锁


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

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

    线程中互斥锁与进程的信号量类似,也可以看做是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!

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

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

  • 相关阅读:
    HTML总结
    Java 基础知识总结 (三、运算符)
    关于JS 事件冒泡和onclick,click,on()事件触发顺序
    Java 基础知识总结 (四、String)
    Java 基础知识总结 (二、基本数据类型)
    websocket实例(显示文件导入处理进度)
    Java 基础知识总结 (一、标识符)
    Java Calendar 注意事项
    Ajax调用SpringMVC ModelAndView 无返回情况
    关于Ajax load页面中js部分$(function(){})的执行顺序
  • 原文地址:https://www.cnblogs.com/binchen-china/p/5453114.html
Copyright © 2020-2023  润新知