【多线程】学习14
做个小总结:
如果拿现实生活中的东西比喻,那么关键段、互斥量、事件、信号量都是什么呢?
感觉事件像是个暂停继续键,
WaitForSingleObject 是暂停
SetEvent 是 继续 可以多次的按继续 但是如果中间没有过暂停的化没有意义
继续的目的是为了等条件满足,所以事件的意义在于找到线程之间的等待关系。
在同一个线程中对同一个事件同时用SetEvent 和 WaitForSingleObject没什么意义
ResetEvent 是?
后面类比不出来了.....
互斥量的WaitForSingleObject-->ReleaseMute,关键段的EnterCriticalSection-->LeaveCriticalSection,都是必须在同一个线程内执行,线程A拥有了资源的所有权,那么释放所有权也必须由线程A来执行
互斥量和关键段的用途好像,除了用户对象内核对象的差别 是否跨线程 处理遗弃的差别 功能上有什么本质不同吗?
参看了:http://www.cnblogs.com/huhuuu/p/3589590.html 里面举了个互斥量和关键段在同一进程中同样使用时效果不同的例子:
个人用比较常见的生成者消费者模型稍作变型,成了4个生产者,4个消费者,4个临界区资源:
用信号量full,empty表示临界区的资源,用关键段处理对变量的互斥访问。
#include<stdio.h> #include<process.h> #include<windows.h> volatile long g_nLoginCount; const int THREAD_NUM = 10; volatile long g_num; HANDLE g_Mutex; HANDLE g_Semaphore_full,g_Semaphore_empty; //信号量 CRITICAL_SECTION g_thread; int num=10; unsigned int __stdcall producer(void *pPM){ int i; for(i=0;i<4;i++){ Sleep(100); WaitForSingleObject(g_Semaphore_empty,INFINITE); Sleep(100);
printf("生产者ID:%d\n", GetCurrentThreadId());
// EnterCriticalSection(&g_thread); //用关键段不会有问题 WaitForSingleObject(g_Mutex,INFINITE); //用互斥量就会出问题 g_num++; printf("生产者ID:%d 累积SUM : %d\n",GetCurrentThreadId(),g_num); ReleaseMutex(&g_Mutex); // LeaveCriticalSection(&g_thread); ReleaseSemaphore(g_Semaphore_full,1,NULL);//信号量++ Sleep(10); } return 0; } unsigned int __stdcall customer(void *pPM){ int ok=1; while(1){ //Sleep(0); Sleep(100); Sleep(0); WaitForSingleObject(g_Semaphore_full,INFINITE); printf(" 消费者ID:%d 累积SUM : %d\n",GetCurrentThreadId(),g_num); ReleaseSemaphore(g_Semaphore_empty,1,NULL);//信号量++ } return 0; } int main(){ g_Semaphore_full = CreateSemaphore(NULL,0,4,NULL);//当前0个资源,最大允许4个同时访 g_Semaphore_empty = CreateSemaphore(NULL,0,4,NULL);//当前0个资源,最大允许4个同时访 g_Mutex = CreateMutex(NULL,FALSE,NULL); InitializeCriticalSection(&g_thread); HANDLE handle[10]; ReleaseSemaphore(g_Semaphore_empty,4,NULL);//信号量++ int i; for(i=0;i<4;i++){ handle[i] = (HANDLE)_beginthreadex(NULL,0,producer,NULL,0,NULL); } for(i=0;i<4;i++){ handle[i+4] = (HANDLE)_beginthreadex(NULL,0,customer,NULL,0,NULL); } WaitForMultipleObjects(THREAD_NUM,handle,TRUE,INFINITE); getchar(); //一定要在这里设置使主线程停止,否则执行到后面的话,子线程就被关闭了 for(i=0;i<6;i++) CloseHandle(handle[i]); CloseHandle(g_Semaphore_full); CloseHandle(g_Semaphore_empty); CloseHandle(g_Mutex); return 0; }
用互斥量效果见左图 关键段效果见右图
使用互斥量的输出完全变成有序的了,这不应该啊。 根据输出,开始4个生产线程先后想要加锁,一个线程赢了,但是后面该线程解锁后理论上应该其他
三个已经在等待的线程加锁,但实际上却还是这个已经拥有了互斥量的线程赢了??
有想过是因为互斥量有所有权,在多个等待时优先选择自己,但是试了试下面的代码,却没有这个问题了。
#include <Windows.h> #include <process.h> #include <stdio.h> int tickets = 100; HANDLE hMutex; DWORD WINAPI Thread1Fun(LPVOID lpParam) { while(1) { WaitForSingleObject(hMutex, INFINITE); if(tickets > 0) { printf("ID = %d t1 = %d\n", GetCurrentThreadId(),tickets--); } else { break; } ReleaseMutex(hMutex); Sleep(100); } return 0; } DWORD WINAPI Thread2Fun(LPVOID lpParam) { while (true) { WaitForSingleObject(hMutex,INFINITE); if (tickets>0) { printf("ID = %d t2 = %d\n", GetCurrentThreadId(), tickets--); } else { break; } ReleaseMutex(hMutex); Sleep(100); } return 0; } int main() { HANDLE hThread1, hThread2, hThread3, hThread4; hThread1 = CreateThread(NULL, 0, Thread1Fun, NULL, 0, NULL); hThread2 = CreateThread(NULL, 0, Thread2Fun, NULL, 0, NULL); hThread3 = CreateThread(NULL, 0, Thread1Fun, NULL, 0, NULL); hThread4 = CreateThread(NULL, 0, Thread2Fun, NULL, 0, NULL); CloseHandle(hThread1); CloseHandle(hThread2); CloseHandle(hThread3); CloseHandle(hThread4); hMutex = CreateMutex(NULL, FALSE, NULL); //TRUE代表主线程拥有互斥对象 但是主线程没有释放该对象 互斥对象谁拥有 谁释放 //FLASE代表当前没有线程拥有这个互斥对象 Sleep(40000); return 0; }
同样是一个线程里面互斥量用了很多遍,为什么这个代码的结果就是无序的?
有线程所有权的:关键段、互斥量
处理情况的区分:
事件: 例如水烧开了才能下面条。
下面条_线程
WaitFor(水烧开) 下面条
烧水线程
烧水 Set(水烧开)
处理的事情有时间先后的关系,若是在一个线程里面就是顺序执行,多个线程里面就需要同步。
信号量: 食堂打饭的时候,有个放菜的区域,只要区域里有菜大家就都可以拿,只要区域里有空地就可以放菜。
若满了就不能放菜了,若空了顾客就拿不了菜了。 信号量有个容量的概念。