VC實現線程同步(或異步)

操作系統裏講的的進程同步,用的是信號燈,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),有問題,反正對臨界區變量的操作都放在臨界區段,纔會沒問題。

另外同步和異步差不多,同步只是要控制各自前進的步伐,可以認爲是交替異步,需要控制步伐的異步,比如典型的生產者和消費者模型,消費過程前進到‘沒有產品剩餘的時候’就要控制步伐,同樣的道理,生產者生產到倉庫裏裝滿產品的時候也要控制一下,這就是同步。相比之下異步要簡單得多,只要讓公共數據的操作放在臨界區段內就行了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章