操作系统里讲的的进程同步,用的是信号灯,PV操作,P操作看成是申请资源,V操作是看成是交还资源,资源可以有很多解释,比如时间,空间,数据等,而信号量可以看成是资源数目。 在WIN32里多进程用得少,因为进程建立很费劲,分配虚拟内在是其中一个原因,取而代之的是线程,线程可以看成是小进程,是一个进程中活的东西,进程是死的,占有了内存和得到了一些系统资源后就死了,只有启动主线程的时候才活起来,主线程的地位相当重要,主线程一结束进程也就被OS踢出去了。进程间也可以通信,当然要复杂一些,因为地址空间完全不同,用得多的有管道等。 1,互斥对象 一个互斥对象,维护一组数据:当前线程,使用计数,受信状态。PV操作相当于:WaitForSingleObject()和ReleaseMutex(),ReleaseMutex()不一定会将Mutex Release掉,如果计数为1,才会将线程ID改为0,并改受信状态为signed。建立的语句是CreateMutex,释放资源是CloseHandle,进程退出的时候也会自动释放。 2,事件对象 事件对象分两种,一种是人工重置的(ManualReset),影响到WaitForSingleObject()的时候是否由系统设为unsigned,这里有个值得思考的情况: a,When "Non-ManualReset" use WaitForSingleObject(event1); b,When "ManualReset" use WaitForSingleObject(event1); ResetEvent(event1); 他们是不是等价的呢?看起来,如果人工重置的,在WaitForSingleObject()后紧接着就ResetEvent(),那不就是系统自动的了吗? 这是不等价的,原因是,在调用完WaitForSingleObject()后,在进入ResetEvent()之前,是有可能被系统的线程调度程序给设成‘就绪’状态,其它的线程执行,这时候又是signed,所以就出问题了。 3,临界区段 临界区程序就是有线程在处理相同的数据,如果线程都在跑各自不同的数据,那异步是完全没有问题的,如果跑相同的程序,就可能有问题,相当于线程撞在了一起,所以叫临界区。用InitializeCriticalSection创建,DeleteCriticalSection释放,进入临界区是EnterCriticalSection,离开是LeaveCriticalSection。感觉这跟互斥对象是一样的,也有个计数器在维护。 下面是两个线程异步售票的程序: #include "stdafx.h"#include "windows.h"CRITICAL_SECTION g_cs;int tickets=200;HANDLE g_event_finish;DWORD WINAPI ThreadProc1( LPVOID lpParameter // thread data){// while(tickets>0) while(TRUE) { EnterCriticalSection(&g_cs); if(tickets>0) printf("Thread 1 sell tickets %d\n",tickets--); else break; LeaveCriticalSection(&g_cs); } printf("tickets sold out\n"); SetEvent(g_event_finish); return 0;}DWORD WINAPI ThreadProc2( LPVOID lpParameter // thread data){// while(tickets>0) while(TRUE) { EnterCriticalSection(&g_cs); if(tickets>0) printf("Thread 2 sell tickets %d\n",tickets--); else break; LeaveCriticalSection(&g_cs); } printf("tickets sold out\n"); SetEvent(g_event_finish); return 0;} int main(int argc, char* argv[]){ InitializeCriticalSection(&g_cs); g_event_finish=CreateEvent(NULL,TRUE,FALSE,NULL); HANDLE h1=CreateThread(NULL,0,ThreadProc1,0,0,NULL); HANDLE h2=CreateThread(NULL,0,ThreadProc2,0,0,NULL); CloseHandle(h1); CloseHandle(h2); WaitForSingleObject(g_event_finish,INFINITE); DeleteCriticalSection(&g_cs); return 0;} 原来用的while(tickets>0),有问题,反正对临界区变量的操作都放在临界区段,才会没问题。 另外同步和异步差不多,同步只是要控制各自前进的步伐,可以认为是交替异步,需要控制步伐的异步,比如典型的生产者和消费者模型,消费过程前进到‘没有产品剩余的时候’就要控制步伐,同样的道理,生产者生产到仓库里装满产品的时候也要控制一下,这就是同步。相比之下异步要简单得多,只要让公共数据的操作放在临界区段内就行了。

评论