电竞比分网-中国电竞赛事及体育赛事平台

分享

VC windows api 多線程---互斥量、信號(hào)量、臨界值

 恩賜野兔 2011-06-22
VC windows api 多線程---互斥量


    互斥量的用途和臨界區(qū)很像。它與臨界區(qū)的差別在于可以跨線程使用,可以用來(lái)同步進(jìn)行多個(gè)線程間的數(shù)據(jù)訪問(wèn),但是是以犧牲速度為代價(jià)的。只有臨界區(qū)是非核心對(duì)象,那么互斥量就是一個(gè)核心對(duì)象了。核心對(duì)象的特點(diǎn)是有所謂的引用計(jì)數(shù)。所著一個(gè)未被擁有的互斥量,比鎖住一個(gè)未被擁有的臨界區(qū)需要花費(fèi)幾乎100倍的時(shí)間(數(shù)據(jù)引用自《Visual C++ 6.0編程學(xué)習(xí)捷徑》)。

 Win32 API有一套互斥量的支持函數(shù):


創(chuàng)建互斥量.
 * @param lpMutexAttributes 指定安全屬性,NULL表示使用默認(rèn)的屬性.
 * @param bInitialOwner 指出創(chuàng)建互斥量的線程是否要成為該互斥量的最初擁有.
 * TRUE表示擁有,因此互斥量將處于無(wú)信號(hào)狀態(tài).
 * FALSE表示互斥量不被任何現(xiàn)成擁有,因此處于有信號(hào)狀態(tài).
 * @param lpName為NULL或標(biāo)識(shí)該互斥量的一個(gè)字符串的地址,任何進(jìn)程或線程都可以根據(jù)此名稱使用該互斥量.
 * 當(dāng)應(yīng)用程序調(diào)用CreateMutex()函數(shù)時(shí),系統(tǒng)分配一個(gè)互斥量的核心對(duì)象,把它的名字設(shè)為lpName所致的字符串.
 * 該名字在進(jìn)程間共享互斥量。CreateMutex()返回一個(gè)標(biāo)識(shí)新互斥量對(duì)象的進(jìn)程相關(guān)的句柄.
HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCTSTR lpName);

 

打開互斥量.
 * @param dwDesiredAccess 可設(shè)置為MUTEX_ALL_ACCESS或SYNCHRONIZE.
 * @param bInheritHandle 指出該進(jìn)程創(chuàng)建的子進(jìn)程能否繼承該互斥量.
 * @param lpName 指定互斥量的名字.
HANDLE OpenMutex(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName);

 

釋放互斥量.
 * @param hMutex 要釋放的互斥量的句柄.
BOOL ReleaseMutex(HANDLE hMutex);

 

 

 

-------------------------------------------
#include <stdio.h>
#include <windows.h>
#include <string.h>
#include <stdlib.h>

#define  threadnum 10

typedef struct THREADDATA
{
   int id;
   char name[10];
   int sleep;
}THREADDATA;


HANDLE handleMutex;

char * str;

DWORD WINAPI ThreadProc( LPVOID lpParam )
{
   THREADDATA *data=(THREADDATA *)lpParam;
   //WaitForSingleObject(handleMutex,INFINITE);
   for(int i=0;i<10;i++)
   {
    WaitForSingleObject(handleMutex,INFINITE);
    printf("thread%d:%d\n",data->id,i);
    ReleaseMutex(handleMutex);
    Sleep(data->sleep);

   }
 //  ReleaseMutex(handleMutex);
   return 0;
}

int main(int argc, char* argv[])
{
   str=(char*)malloc(30);
   THREADDATA  pData[threadnum];
   DWORD dwThreadId[threadnum];
   HANDLE hThread[threadnum]; 

   handleMutex= CreateMutex(NULL,false,NULL);

   for(int i=0;i<threadnum;i++)
   {
     pData[i].id=i;
     sprintf(pData[i].name,"yuguoqing");
     pData[i].sleep=i*10;
     hThread[i] = CreateThread(NULL,0,ThreadProc, pData+i, 0,  dwThreadId+i);
   }

    WaitForMultipleObjects(threadnum, hThread, TRUE, INFINITE);

    return 0;
} 

VC windows api 多線程---信號(hào)量

 


信號(hào)量(Semaphore)和互斥量一樣,屬于內(nèi)核對(duì)象。它自動(dòng)執(zhí)行可用資源查詢的測(cè)試,如果有可用資源,則可用資源的計(jì)數(shù)減少,從而避免其它線程請(qǐng)求資源。當(dāng)該線程釋放該資源后,可用資源計(jì)數(shù)增加,則操作系統(tǒng)允許另一個(gè)線程請(qǐng)求資源。

信號(hào)量與臨界區(qū)和互斥量的不同在于,它不能被認(rèn)為屬于某個(gè)線程。也就是說(shuō),一個(gè)線程可以等待信號(hào)量對(duì)象(減少它的資源計(jì)數(shù)),而另一個(gè)線程釋放該對(duì)象(增加它的資源計(jì)數(shù))。

Win32 API提供了幾個(gè)函數(shù)用于支持信號(hào)量。使用Win32 API產(chǎn)生一個(gè)信號(hào)量,必須首先調(diào)用CreateSemaphore()函數(shù),該函數(shù)描述如下:

創(chuàng)建一個(gè)信號(hào)量
 
*@param lpSemaphoreAttributes 指定安全屬性,如果是NULL就表示使用默認(rèn)屬性。
 
*@param lInitialCount 用于指定該信號(hào)量的初始資源計(jì)數(shù),必須大于或等于0,并且小于或等于lMaximumCount。
 
*@param lMaximumCount 指定信號(hào)量的最大資源計(jì)數(shù)。
 
*@param lpName 是賦給信號(hào)量的字符串名字。
HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCTSTR lpName);     

 

你可以根據(jù)信號(hào)量的字符串名字得到該信號(hào)量的句柄: 
 
*@param dwDesiredAccess 訪問(wèn)方式,同互斥量參數(shù)。
 
*@param bInheritHandle 繼承特性,同互斥量參數(shù)。
 
*@param lpName 信號(hào)量名字。
HANDLE OpenSemaphore(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName);     

 

釋放信號(hào)量函數(shù):
 
*@param hSemaphore 信號(hào)量的句柄。
 
*@param lReleaseCount指信號(hào)量現(xiàn)值的增額,該值必須大于0。
 
*@param lpPreviousCount 傳回信號(hào)量原來(lái)的計(jì)數(shù),可以為NULL。
BOOL ReleaseSemaphore(HANDLE hSemaphore, LONG lReleaseCount, LPLONG lpPreviousCount);
      
釋放信號(hào)量函數(shù)與釋放互斥量函數(shù)形式相同,但不同之處在于:
一、任意線程可以在任意時(shí)刻調(diào)用此函數(shù),因?yàn)樾盘?hào)量對(duì)象不為某個(gè)線程擁有。
二、ReleaseSemaphore()函數(shù)可以用大于1的大小來(lái)增加信號(hào)量的資源計(jì)數(shù)。


---------------------------------------

#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
#include <string.h>
#include <stdlib.h>

#define  threadnum 10

typedef struct THREADDATA
{
   int id;
   char name[10];
   int sleep;
}THREADDATA;


HANDLE handleSemaphore;
char * str;

DWORD WINAPI ThreadProc( LPVOID lpParam )
{
   THREADDATA *data=(THREADDATA *)lpParam;
 
   WaitForSingleObject(handleSemaphore,INFINITE);
   for(int i=0;i<10;i++)
   {
 // WaitForSingleObject(handleSemaphore,INFINITE);
   printf("thread%d:%d\n",data->id,i);
 // ReleaseSemaphore(handleSemaphore,1,NULL);
   Sleep(data->sleep);

   }
   ReleaseSemaphore(handleSemaphore,1,NULL);
   return 0;
}

int main(int argc, char* argv[])
{
   str=(char*)malloc(30);
   THREADDATA  pData[threadnum];
   DWORD dwThreadId[threadnum];
   HANDLE hThread[threadnum];

   handleSemaphore=CreateSemaphore(NULL,1, 2,"thread");

   for(int i=0;i<threadnum;i++)
   {
     pData[i].id=i;
     sprintf(pData[i].name,"yuguoqing");
     pData[i].sleep=i*10;
     hThread[i] = CreateThread(NULL,0,ThreadProc, pData+i, 0,  dwThreadId+i);
   }

    WaitForMultipleObjects(threadnum, hThread, TRUE, INFINITE);
    return 0;
}

VC windows api 多線程---臨界區(qū)



在有幾個(gè)線程并行運(yùn)行的環(huán)境中,同步不同線程的活動(dòng)是非常重要的。一般說(shuō)來(lái),一個(gè)線程使自己與另一個(gè)線程同步的方法是讓自己睡眠。但線程睡眠時(shí),操作系統(tǒng)不再為它調(diào)度CPU時(shí)間,因此它停止了執(zhí)行。不過(guò),就在它睡眠之前,它告訴系統(tǒng)要讓它恢復(fù)執(zhí)行,必須有什么“特殊事件”發(fā)生。操作系統(tǒng)記住該線程的請(qǐng)求,監(jiān)視著“特殊事件”是否發(fā)生以及何時(shí)發(fā)生。當(dāng)它發(fā)生時(shí),線程才又能夠加入到CPU時(shí)間等待隊(duì)列中。一旦被預(yù)訂,線程就能繼續(xù)執(zhí)行了。此時(shí),線程就將它的執(zhí)行與時(shí)間的發(fā)生取得了同步。

    Windows操作系統(tǒng)提供了設(shè)定“特殊事件”的方法,就是使用同步對(duì)象。我將在今后學(xué)習(xí)常用的四種同步對(duì)象:臨界區(qū)(Critical Section)、互斥量(Mutex)、信號(hào)量(Semaphore)、事件(Event)。

    上述四種同步對(duì)象,除了臨界區(qū)外都是內(nèi)核對(duì)象。臨界區(qū)不被操作系統(tǒng)的低級(jí)部件管理,而且不能使用句柄來(lái)操縱,是最易于使用和理解的同步對(duì)象。

    當(dāng)多個(gè)線程共享對(duì)同一數(shù)據(jù)的訪問(wèn)時(shí),線程之間可能會(huì)有干擾。一個(gè)臨界區(qū)對(duì)象保護(hù)一段代碼不被多于一個(gè)線程訪問(wèn)。在所有的同步對(duì)象中,臨界區(qū)是最容易使用的,但是,一個(gè)臨界區(qū)對(duì)一個(gè)進(jìn)程或DLL是有限的,不能被其他進(jìn)程共享,只能用于同步單個(gè)進(jìn)程中的線程。臨界區(qū)不是Windows核心對(duì)象,它和核心對(duì)象不同,存在于進(jìn)程的內(nèi)存空間中。

    Win32 API提供了幾個(gè)臨界區(qū)函數(shù):

void InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
void EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
void LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
void DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection);

    CRITICAL_SECTION類型的變量用來(lái)扮演紅綠燈的角色,讓同一個(gè)時(shí)間內(nèi)只有一個(gè)線程進(jìn)入臨界區(qū)。該臨界區(qū)變量的聲明必須是全局的,這樣不同的線程就能訪問(wèn)它。操縱臨界區(qū)的Win32函數(shù)初始化和維護(hù)該結(jié)構(gòu)中的所有成員,不要自己去訪問(wèn)和修改任何成員。

    使用臨界區(qū)之前,必須調(diào)用InitializeCriticalSection()函數(shù)來(lái)初始化臨界區(qū)。而通過(guò)調(diào)用EnterCriticalSection()函數(shù)來(lái)取得一個(gè)臨界區(qū)的所有權(quán)。然后通過(guò)LeaveCriticalSection()函數(shù)來(lái)釋放所有權(quán)。臨界區(qū)通過(guò)一個(gè)線程取得所有權(quán)來(lái)顯示它已經(jīng)進(jìn)入代碼臨界區(qū)的方法進(jìn)行工作,如果其他線程調(diào)用EnterCriticalSection()并引用同一臨界區(qū),它會(huì)被阻塞,直到第一個(gè)線程調(diào)用LeaveCriticalSection()函數(shù)。最后,可以調(diào)用DeleteCriticalSection()函數(shù)來(lái)釋放用戶初始化臨界區(qū)時(shí)分配的系統(tǒng)資源。

   
    在MFC中封裝了CCriticalSection類作為臨界區(qū)對(duì)象,在構(gòu)造函數(shù)中自動(dòng)調(diào)用InitialCriticalSection()函數(shù),在析構(gòu)函數(shù)中自動(dòng)調(diào)用LeaveCriticalSection()函數(shù),用Lock()和Unlock()對(duì)應(yīng)取得所有權(quán)和釋放所有權(quán)。

 

----------------------------------------------

#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
#include <string.h>
#include <stdlib.h>

#define  threadnum 10

typedef struct THREADDATA
{
   int id;
   char name[10];
   int sleep;
}THREADDATA;

CRITICAL_SECTION sec1;

char * str;

DWORD WINAPI ThreadProc( LPVOID lpParam )
{
   THREADDATA *data=(THREADDATA *)lpParam;
   printf("%d\n%s\n",data->id,data->name);
   EnterCriticalSection(&sec1);
   for(int i=0;i<10;i++)
   {
 //  EnterCriticalSection(&sec1);
   printf("thread%d:%d\n",data->id,i);
 //  LeaveCriticalSection(&sec1);
   Sleep(data->sleep);

   }
   LeaveCriticalSection(&sec1);

   return 0;
}

int main(int argc, char* argv[])
{
   str=(char*)malloc(30);
   THREADDATA  pData[threadnum];
   DWORD dwThreadId[threadnum];
   HANDLE hThread[threadnum];

   InitializeCriticalSection(&sec1);
 
   for(int i=0;i<threadnum;i++)
   {
     pData[i].id=i;
     sprintf(pData[i].name,"yuguoqing");
     pData[i].sleep=i*10;
     hThread[i] = CreateThread(NULL,0,ThreadProc, pData+i, 0,  dwThreadId+i);
   }

    WaitForMultipleObjects(threadnum, hThread, TRUE, INFINITE);

 return 0;
}

轉(zhuǎn)載http://blog.sina.com.cn/s/blog_5040a4e90100gntv.html

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多