windows C++ 用信号量控制线程

时间:2021-04-09 18:32:08
windows C++ 用信号量控制线程 2010-08-11 09:09

很好的控制线程,让线程互斥,互相协调工作,共享数据,这个问题有很多种解决办法,不过我个人觉得使用信号量控制线程特别方便。会想到用多线程控制程序,是由于上学期我们要做一个控制电机转速的课程设计,开始编写的程序都是一个线程控制的。后来课程设计结束了,一次在看多线程的演示程序的时候突然想到,原来的那个电机控制程序完全可以写成多线程,可是由于课程设计结束了,没有硬件供你调试,就自己写了个多线程的练习程序。
控制信号量几个主要的函数:

Cpp代码
  1. WaitForSingleObject();//等待信号量有效  
  2. CreatSemaphore();//申请信号量  
  3. OpenSemaphore();//打开信号量  
  4. ReleaseSemaphore();//释放信号量  


下面来看看控制多线程要用到的东西:

Cpp代码
  1. HANDLE ptrSpdUpDown;   
  2. HANDLE ptrUpDownDraw;   
  3. HANDLE ptrDrawSpd;//申请指向信号量的句柄   
  4.    ptrSpdUpDown = ::CreateSemaphore(NULL, 0, 1, NULL);   
  5.    ptrUpDownDraw = ::CreateSemaphore(NULL, 0, 1, NULL);   
  6.    ptrDrawSpd = ::CreateSemaphore(NULL, 1, 1, NULL);//实例化三个信号量  
  7.   
  8. bOnOff=true;//线程状态控制量 开启三个线程  
  9.      m_tWriteSpeed=AfxBeginThread(WriteSpeed,   
  10.        &m_sWriteSpeed,   
  11.        THREAD_PRIORITY_NORMAL,   
  12.        0,   
  13.        CREATE_SUSPENDED);   
  14.      m_tWriteSpeed->ResumeThread();   
  15.      m_tWriteUpDown=AfxBeginThread(WriteUpDown,   
  16.        &m_sWriteUpDown,   
  17.        THREAD_PRIORITY_NORMAL,   
  18.        0,   
  19.        CREATE_SUSPENDED);   
  20.      m_tWriteUpDown->ResumeThread();   
  21.      m_tDrawWindow=AfxBeginThread(DrawWindow,   
  22.        &m_sDrawWindow,   
  23.        THREAD_PRIORITY_NORMAL,   
  24.        0,   
  25.        CREATE_SUSPENDED);   
  26.      m_tDrawWindow->ResumeThread();   
  27.   
  28. //三个线程函数   
  29. UINT WriteSpeed(LPVOID p)   
  30. {   
  31.   int iNo=1;   
  32.    CString sTr;   
  33.    CString sMe;   
  34.    CEdit *ptr=(CEdit *)p;   
  35.   while(bOnOff)   
  36.    {   
  37.      WaitForSingleObject(ptrDrawSpd,INFINITE);   
  38.      ptr->SetWindowText("线程WriteSpeed正在运行"+sTr+"---Speed:"+sMe+"已经接到信号");   
  39.      ::Sleep(1000);   
  40.      srand((int)time(0));//种种子数  
  41.      iSpeed=iUp+iDown+rand();   
  42.      ReleaseSemaphore(ptrSpdUpDown,1,NULL);   
  43.      sTr.Format("%d",iNo);   
  44.      sMe.Format("%d",iSpeed);   
  45.      ptr->SetWindowText("线程WriteSpeed正在运行"+sTr+"---Speed:"+sMe);   
  46.      iNo++;   
  47.    }   
  48.   return 0;   
  49. }   
  50. UINT WriteUpDown(LPVOID p)   
  51. {   
  52.   int iNo=1;   
  53.    CString sTr;   
  54.    CString sMe;   
  55.    CEdit *ptr=(CEdit *)p;   
  56.   while(bOnOff)   
  57.    {   
  58.      WaitForSingleObject(ptrSpdUpDown,INFINITE);   
  59.      ptr->SetWindowText("线程WriteUpDown正在运行"+sTr+"---Up:"+sMe+"已经接到信号");   
  60.      ::Sleep(1000);   
  61.      srand((int)time(0));//种种子数  
  62.      iUp=iSpeed-rand();   
  63.      iDown=iSpeed+rand();   
  64.      ReleaseSemaphore(ptrUpDownDraw,1,NULL);   
  65.      sTr.Format("%d",iNo);   
  66.      sMe.Format("%d",iUp);   
  67.      ptr->SetWindowText("线程WriteUpDown正在运行"+sTr+"---Up:"+sMe);   
  68.      iNo++;   
  69.    }   
  70.   return 0;   
  71. }   
  72. UINT DrawWindow(LPVOID p)   
  73. {   
  74.   int iNo=1;   
  75.    CString sTr;   
  76.    CEdit *ptr=(CEdit *)p;   
  77.   while(bOnOff)   
  78.    {   
  79.      WaitForSingleObject(ptrUpDownDraw,INFINITE);   
  80.      ptr->SetWindowText("线程DrawWindow正在运行"+sTr+"已经接到信号");   
  81.      ::Sleep(1000);   
  82.      sTr.Format("%d",iNo);   
  83.      ptr->SetWindowText("线程DrawWindow正在运行"+sTr);   
  84.      iNo++;   
  85.      ReleaseSemaphore(ptrDrawSpd,1,NULL);   
  86.    }   
  87.   return 0;   
  88. }  

上面的方法是先申请信号量的句柄然后再实例化信号量 下面这种方法是直接申请信号量 两种方法基本相同

Cpp代码
  1. CSemaphore ptrSpdUpDown(0, 1);   
  2. CSemaphore ptrUpDownDraw(0, 1);   
  3. CSemaphore ptrDrawSpd(1, 1);//#include <atlsync.h>注意在stdafx.h手动包含这个文件  

在各个线程函数中不用WaitForSingleObject了要使用Lock()UnLock();
下面是使用CSemaphore后在各个线程函数中使用Lock()UnLock()替换掉WaitForSingleObject的结果

Cpp代码
  1. UINT WriteSpeed(LPVOID p)   
  2. {   
  3.   int iNo=1;   
  4.    CString sTr;   
  5.    CString sMe;   
  6.    CEdit *ptr=(CEdit *)p;   
  7.   while(bOnOff)   
  8.    {   
  9.      <STRONG>ptrDrawSpd.Lock();</STRONG>   
  10.      ptr->SetWindowText("线程WriteSpeed正在运行"+sTr+"---Speed:"+sMe+"已经接到信号");   
  11.      ::Sleep(1000);   
  12.      srand((int)time(0));//种种子数  
  13.      iSpeed=iUp+iDown+rand();   
  14.      ReleaseSemaphore(ptrSpdUpDown,1,NULL);   
  15.      <STRONG>ptrSpdUpDown.Unlock();</STRONG>   
  16.      sTr.Format("%d",iNo);   
  17.      sMe.Format("%d",iSpeed);   
  18.      ptr->SetWindowText("线程WriteSpeed正在运行"+sTr+"---Speed:"+sMe);   
  19.      iNo++;   
  20.    }   
  21.   return 0;   
  22. }   
  23. UINT WriteUpDown(LPVOID p)   
  24. {   
  25.   int iNo=1;   
  26.    CString sTr;   
  27.    CString sMe;   
  28.    CEdit *ptr=(CEdit *)p;   
  29.   while(bOnOff)   
  30.    {   
  31.      <STRONG>ptrSpdUpDown.Lock();</STRONG>   
  32.      ptr->SetWindowText("线程WriteUpDown正在运行"+sTr+"---Up:"+sMe+"已经接到信号");   
  33.      ::Sleep(1000);   
  34.      srand((int)time(0));//种种子数  
  35.      iUp=iSpeed-rand();   
  36.      iDown=iSpeed+rand();   
  37.      ReleaseSemaphore(ptrUpDownDraw,1,NULL);   
  38.      <STRONG>ptrUpDownDraw.Unlock();</STRONG>   
  39.      sTr.Format("%d",iNo);   
  40.      sMe.Format("%d",iUp);   
  41.      ptr->SetWindowText("线程WriteUpDown正在运行"+sTr+"---Up:"+sMe);   
  42.      iNo++;   
  43.    }   
  44.   return 0;   
  45. }   
  46. UINT DrawWindow(LPVOID p)   
  47. {   
  48.   int iNo=1;   
  49.    CString sTr;   
  50.    CEdit *ptr=(CEdit *)p;   
  51.   while(bOnOff)   
  52.    {   
  53.      <STRONG>ptrUpDownDraw.Lock();</STRONG>   
  54.      ptr->SetWindowText("线程DrawWindow正在运行"+sTr+"已经接到信号");   
  55.      ::Sleep(1000);   
  56.      sTr.Format("%d",iNo);   
  57.      ptr->SetWindowText("线程DrawWindow正在运行"+sTr);   
  58.      iNo++;   
  59.      ReleaseSemaphore(ptrDrawSpd,1,NULL);   
  60.      <STRONG>ptrDrawSpd.Unlock();</STRONG>   
  61. }   
  62.   return 0;   
  63. }  

推荐使用第一种方法,第一种方法只声明了句柄,当信号量实例化的时候句柄才指向三个信号量。所以更加支持多态。