正文

VC实现线程同步(或异步)2007-04-24 22:07:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/rickone/25228.html

分享到:

操作系统里讲的的进程同步,用的是信号灯,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),有问题,反正对临界区变量的操作都放在临界区段,才会没问题。

另外同步和异步差不多,同步只是要控制各自前进的步伐,可以认为是交替异步,需要控制步伐的异步,比如典型的生产者和消费者模型,消费过程前进到‘没有产品剩余的时候’就要控制步伐,同样的道理,生产者生产到仓库里装满产品的时候也要控制一下,这就是同步。相比之下异步要简单得多,只要让公共数据的操作放在临界区段内就行了。

阅读(10311) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册