分享

C/C 临界量

 张岩峰 2011-12-21

1.CRITICAL_SECTION:不能锁定资源,只是同步代码

简单说,当一个线程执行了EnterCritialSection之后,cs里面的信息便被修改了,以指明哪一个线程占用了它。而此时,并没有任何资源被“锁定”。只不过,在这个线程尚未执行LeaveCriticalSection之前,其它线程碰到EnterCritialSection语句的话,就会处于等待状态,相当于线程被挂起了。 这种情况下,就起到了保护共享资源的作用。
也正由于CRITICAL_SECTION是这样发挥作用的,所以,必须把每一个线程中访问共享资源的语句都放在EnterCritialSection和LeaveCriticalSection之间。这是初学者很容易忽略的地方。

CRITICAL_SECTION临界区的使用在线程同步中应该算是比较简单,在使用临界区的时候要注意,每一个共享资源就有一个CRITICAL_SECTION,如果要一次访问多个共享变量,各个线程要保证访问的顺序一致,如果不一致,很可能发生死锁。

   1: InitializeCriticalSection(&g_cs_listview);
   2: InitializeCriticalSectionAndSpinCount(&g_cs_listview);
   3: DeleteCriticalSection(&g_cs_listview);
   4: TryEnterCriticalSection(&g_cs_listview);
   5: EnterCriticalSection(&g_cs_listview);
   6: LeaveCriticalSection(&g_cs_listview);

注意:假如多个线程都在等待同一个critical section,究竟哪个线程会先获得它的所有权是不一定的,cirtical section在这方面没有保证.

 

2.Semaphore信号量:

Semaphore对象用来控制对资源的并发访问数。内部有个计数器,当值>=0设置了信号,==0清除信号。每次调用wait函数计数器都减1。调用ReleaseSemaphore时将计数器设置为lREleaseCount的指定的值。

// 创建信号量,且设置为1表示每次只能有一个线程访问;
// 如果创建失败表示该"semaphore_test"标示符在别的进程中创建,可用OpenSemaphore来打开信号量
// CreateSemaphore(为安全属性,Semaphore的初始值,最大值,对象的名字)
HANDLE hSe = CreateSemaphore(NULL, 1, 1, "semaphore_test");

// 释放本进程的信号量
// ReleaseSemaphore(句柄,要增加的数值,用于返回之前的计算值)
ReleaseSemaphore(hSe, 1, NULL);

// 等待一个对象是否可用;
ret = WaitForSingleObject(hSe, 1000);
case WAIT_OBJECT_0: // 如果是WaitForSingleObject第一个对象就是等待的句柄
case WAIT_TIMEOUT:  // 超时

   1: #include "stdafx.h"
   2: #include <windows.h>
   3: #include <iostream>
   4: using namespace std;
   5:  
   6: const int MAX_RUNNUM = 3;  //最多运行实例个数
   7: void PrintInfo()
   8: {
   9:     char c;
  10:     cout << "run program" << endl;
  11:     cout << "input s to exit program!" << endl;
  12:     while (1)
  13:     {
  14:         cin >> c;
  15:         if (c == 's')
  16:         {
  17:             break;
  18:         }
  19:         Sleep(10);
  20:     }
  21: }
  22: int main(int argc, char* argv[])
  23: {
  24:     HANDLE hSe = CreateSemaphore(NULL, MAX_RUNNUM, MAX_RUNNUM, "semaphore_test");
  25:     DWORD ret = 0;
  26:     if (hSe == NULL)
  27:     {
  28:         cout << "createsemaphore failed with code: " << GetLastError() << endl;
  29:         return -1;
  30:     }
  31:     ret = WaitForSingleObject(hSe, 1000);
  32:     if (ret == WAIT_TIMEOUT)
  33:     {
  34:         cout << "you have runned " << MAX_RUNNUM << " program!" << endl;
  35:         ret = WaitForSingleObject(hSe, INFINITE); 
  36:     }
  37:     PrintInfo();
  38:     ReleaseSemaphore(hSe, 1, NULL);
  39:     CloseHandle(hSe);
  40:     return 0;
  41: }

 

3.Mutex-互斥体

mutex互斥体的意思,当一个线程持有一个Mutex时,其它线程申请持有同一个Mutex会被阻塞在一个队列中,当互斥体释放后队列中的第一个线程首先获得使用权。

//创建一个互斥体
//CreateMutex(安全描述符, Mutex的持有者设置为调用线程, Mutex的名字)
//如果创建失败表示该名称的mutex标示符在别的进程中创建,可用OpenMutex来打开信号量
HANDLE hmutex = CreateMutex(NULL, false, NULL);

//销毁互斥体
CloseHandle(hmutex);

// 等待一个对象是否可用;
ret = WaitForSingleObject(hmutex, 1000);
case WAIT_OBJECT_0: // 如果是WaitForSingleObject第一个对象就是等待的句柄
case WAIT_TIMEOUT:  // 超时

   1: //互斥体通常用于多进程之间的同步问题
   2:  
   3: //程序运行单个实例:
   4: #include "stdafx.h"
   5: #include <windows.h>
   6: #include <process.h>
   7: #include <iostream>
   8: using namespace std;
   9:  
  10: //当输入s或者c时候结束程序
  11: void PrintInfo(HANDLE& h, char t)
  12: {
  13:     char c;
  14:     while (1)
  15:     {
  16:         cin >> c;
  17:         if (c == t)
  18:         {
  19:             ReleaseMutex(h);
  20:             CloseHandle(h);
  21:             break;
  22:         }
  23:         Sleep(100);
  24:     }
  25: }
  26: int main(int argc, char* argv[])
  27: {
  28:     //创建mutex,当已经程序发现已经有这个mutex时候,就相当于openmutex
  29:     HANDLE hHandle = CreateMutex(NULL, FALSE, "mutex_test");
  30:     if (GetLastError() == ERROR_ALREADY_EXISTS)
  31:     {
  32:         cout << "you had run this program!" << endl;
  33:         cout << "input c to close this window" << endl;
  34:         PrintInfo(hHandle, 'c');
  35:         return 1;
  36:     }
  37:     cout << "program run!" << endl;
  38:     cout << "input s to exit program" <<endl;
  39:     PrintInfo(hHandle, 's');
  40:     return 1;
  41: }

 

4.Event事件

创建一个事件:
hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
第1个参数:安全属性大多默认为null
第2个参数:是否必须手工复位到无信号状态,false=线程结束就自动设置无信号
第3个参数:默认是否有信号;true有信号,false无信号
第4个参数:对象名称,大多为null

释放一个事件:
CloseHandle(hEvent);

设置一个事件有信号
setEvent(hEvent);   //变成有信号状态
pluseEvent(hEvent); //一个脉冲:从无信号变成有信号再变成无信号

复位一个Event对象
ResetEvent(hEvent)

 

等待一个或多个事件有信号:
WaitForSingleObject(handle, INFINITE/*等待时间*/);
参数handle:可以(Event,Mutex,Process,Thread,Semaphore)等等; thread的join就是等thread实现的
参数INFINITE:是等待超时时间,INFINITE是死等

WaitForMultipleObjects(nCount, handle_array, false, INFINITE/*等待时间*/);
参数nCount:是监测event的个数
参数handle_array:是event数组
参数false:表示有一个信号就返回,true是等待所有事件都有信号才返回
参数INFINITE:是等待超时时间,INFINITE是死等

wait…返回值
WAIT_OBJECT_0:表示第一个事件
WAIT_TIMEOUT:超时
WAIT_ABANDONED:

   1: /*简单示例,一个线程不停读取用户输入并放入message列表,
   2: 另一个线程模拟将message发送出去,如果没有消息,则发送线程处于阻塞状态等待,
   3: 一旦有消息录入,输入线程将event置位,发送线程即被激活并逐个发送消息。*/
   4: #include "stdafx.h"
   5: #include <windows.h>
   6: #include <tchar.h>
   7: #include <iostream>
   8: #include <list>
   9: #include <string>
  10: using namespace std;
  11:  
  12: #ifdef _UNICODE
  13: typedef wstring tstring;
  14: #define tcout wcout
  15: #define tcin wcin
  16: #else
  17: typedef string tstring;
  18: #define tcout cout
  19: #define tcin cin
  20: #endif /* _UNICODE */
  21:  
  22: typedef list<tstring> StringList;
  23:  
  24: HANDLE hMutex = NULL;
  25: HANDLE hEvent = NULL;
  26: HANDLE hSendThread = NULL;
  27: StringList messages;
  28:  
  29: bool isRunning;
  30:  
  31: DWORD WINAPI SendThreadProc(LPVOID lpThreadParameter)
  32: {
  33:     DWORD dw;
  34:     while(isRunning)
  35:     {
  36:         dw = WaitForSingleObject(hEvent, INFINITE);
  37:         if(dw != WAIT_OBJECT_0)
  38:         {
  39:             tcout << _T("Wait error.") << endl;
  40:             return -1;
  41:         }
  42:         dw = WaitForSingleObject(hMutex, INFINITE);
  43:         if(WAIT_OBJECT_0 != dw && WAIT_ABANDONED != dw)
  44:         {
  45:             tcout << _T("Wait error.") << endl;
  46:             return -2;
  47:         }
  48:  
  49:         StringList list(messages);
  50:         messages.clear();
  51:  
  52:         ReleaseMutex(hMutex);
  53:  
  54:         for(StringList::iterator i = list.begin(); i != list.end(); i++)
  55:         {
  56:             Sleep(1000); //休眠1秒模拟发送所耗时间
  57:  
  58:             tcout << _T("/* Send Message:") << *i << _T(" */");
  59:         }
  60:  
  61:     }
  62:  
  63:     return 0;
  64: }
  65:  
  66: int _tmain(int argc, _TCHAR* argv[])
  67: {
  68:     hMutex = CreateMutex(NULL, FALSE, NULL);
  69:     hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  70:     isRunning = true;
  71:  
  72:     hSendThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SendThreadProc, NULL, 0, NULL);
  73:  
  74:     while(isRunning)
  75:     {
  76:         tstring s;
  77:         tcin >> s;
  78:         if(s == _T("quit"))
  79:         {
  80:             isRunning = true;
  81:             break;
  82:         }
  83:  
  84:         DWORD dw = WaitForSingleObject(hMutex, INFINITE);
  85:         if(WAIT_OBJECT_0 != dw && WAIT_ABANDONED != dw)
  86:         {
  87:             tcout << _T("Wait error.") << endl;
  88:             return -1;
  89:         }
  90:         messages.push_back(s);
  91:         ReleaseMutex(hMutex);
  92:         SetEvent(hEvent);
  93:     }
  94:  
  95:     CloseHandle(hMutex);
  96:     CloseHandle(hEvent);
  97:     CloseHandle(hSendThread);
  98:  
  99:     return 0;
 100: }

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多