亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

? 歡迎來到蟲蟲下載站! | ?? 資源下載 ?? 資源專輯 ?? 關(guān)于我們
? 蟲蟲下載站

?? 進程同步.txt

?? 關(guān)于進程同步的一個程序
?? TXT
字號:
使用臨界段實現(xiàn)優(yōu)化的進程間同步對象-原理和實現(xiàn)

by Jeffrey.Richter 

vcbear 熱情講解

實現(xiàn)自己的同步對象?需要嗎?

不需要嗎?

...

只是跟你研究一下而已.

算了吧我只是個愛灌水的家伙,很久沒有寫代碼了,閑來無事,灌灌水還不行嗎?

 

1.概述:

在多進程的環(huán)境里,需要對線程進行同步.常用的同步對象有臨界段(Critical Section),互斥量(Mutex),信號量(Semaphore),事件(Event)等,除了臨界段,都是內(nèi)核對象。

在同步技術(shù)中,臨界段(Critical Section)是最容易掌握的,而且,和通過等待和釋放內(nèi)核態(tài)互斥對象實現(xiàn)同步的方式相比,臨界段的速度明顯勝出.但是臨界段有一個缺陷,WIN32文檔已經(jīng)說明了臨界段是不能跨進程的,就是說臨界段不能用在多進程間的線程同步,只能用于單個進程內(nèi)部的線程同步.

因為臨界段只是一個很簡單的數(shù)據(jù)結(jié)構(gòu)體,在別的進程的進程空間里是無效的。就算是把它放到一個可以多進程共享的內(nèi)存映象文件里,也還是無法工作.

有甚么方法可以跨進程的實現(xiàn)線程的高速同步嗎?

2.原理和實現(xiàn)

2.1為什么臨界段快? 是“真的”快嗎?

確實,臨界段要比其他的核心態(tài)同步對象要快,因為EnterCriticalSection和LeaveCriticalSection這兩個函數(shù)從InterLockedXXX系列函數(shù)中得到不少好處(下面的代碼演示了臨界段是如何使用InterLockedXXX函數(shù)的)。InterLockedXXX系列函數(shù)完全運行于用戶態(tài)空間,根本不需要從用戶態(tài)到核心態(tài)

之間的切換。所以,進入和離開一個臨界段一般只需要10個左右的CPU執(zhí)行指令。而當(dāng)調(diào)用WaitForSingleObject之流的函數(shù)時,因為使用了內(nèi)核對象,線程被強制的在用戶態(tài)和核心態(tài)之間變換。在x86處理器上,這種變換一般需要600個CPU指令。看到這里面的巨大差距了把。

話說回來,臨界段是不是真正的“快”?實際上,臨界段只在共享資源沒有沖突的時候是快的。當(dāng)一個線程試圖進入正在被另外一個線程擁有的臨界段,即發(fā)生競爭沖突時,臨界段還是等價于一個event核心態(tài)對象,一樣的需要耗時約600個CPU指令。事實上,因為這樣的競爭情況相對一般的運行情況來說是很少的(除非人為),所以在大部分的時間里(沒有競爭沖突的時候),臨界段的使用根本不牽涉內(nèi)核同步,所以是高速的,只需要10個CPU的指令。(bear說:明白了吧,純屬玩概率,Ms的小花招)

2.3進程邊界怎么辦?

“臨界段等價于一個event核心態(tài)對象”是什么意思?

看看臨界段結(jié)構(gòu)的定義先

typedef struct _RTL_CRITICAL_SECTION {

PRTL_CRITICAL_SECTION_DEBUG DebugInfo;

//

// The following three fields control entering and exiting the critical

// section for the resource

//

LONG LockCount;

LONG RecursionCount;

HANDLE OwningThread; // from the thread''s ClientId->UniqueThread

HANDLE LockSemaphore;

DWORD SpinCount;

} RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;

#typedef RTL_CRITICAL_SECTION CRITICL_SECTION

在CRITICAL_SECTION 數(shù)據(jù)結(jié)構(gòu)里,有一個Event內(nèi)核對象的句柄(那個undocument的結(jié)構(gòu)體成員LockSemaphore,包含的實際是一個event的句柄, 而不是一個信號量semaphore)。正如我們所知,內(nèi)核對象是系統(tǒng)全局的,但是該句柄是進程所有的,而不是系統(tǒng)全局的。所以,就算把一個臨界段結(jié)構(gòu)直接放到共享的內(nèi)存映象里,臨界段也無法起作用,因為LockSemaphore里句柄值只對一個進程有效,對于別的進程是沒有意義的。 在一般的進程同步中,進程要使用一個存在于別的進程里的Event 對象,必須調(diào)用OpenEvent或CreaetEvent函數(shù)來得到進程可以使用的句柄值。

CRITICAL_SECTION結(jié)構(gòu)里其他的變量是臨界段工作所依賴的元素,Ms也“警告”程序員不要自己改動該結(jié)構(gòu)體里變量的值。是怎么實現(xiàn)的呢?看下一步.

2.4 COptex,優(yōu)化的同步對象類

Jeffrey Richter曾經(jīng)寫過一個自己的臨界段,現(xiàn)在,他把他的臨界段改良了一下,把它封裝成一個COptex類。成員函數(shù)TryEnter擁有NT4里介紹的函數(shù)TryEnterCriticalSection的功能,這個函數(shù)嘗試進入臨界段,如果失敗立刻返回,不會掛起線程,并且支持Spin計數(shù).這個功能在NT4/SP3中被InitializeCriticalSectionAndSpinCount 和SetCriticalSectionSpinCount實現(xiàn)。Spin計數(shù)在多處理器系統(tǒng)和高競爭沖突情況下是很有用的,在進入WaitForXXX核心態(tài)之前,臨界段根據(jù)設(shè)定的Spin計數(shù)進行多次TryEnterCtriticalSection,然后才進行堵塞。想一下,TryEnterCriticalSection才使用10個左右的周期,如果在Spin計數(shù)消耗完之前,沖突消失,臨界段對象是空閑的,那么再用10個CPU周期就可以在用戶態(tài)進入臨界段了,不用切換到核心態(tài).

(bear說:為了避免這個"核心態(tài)",Ms自己也是費勁腦汁呀.看出來了吧,優(yōu)化的原則:在需要的時候才進入核心態(tài)。否則,在用戶態(tài)進行同步)

以下是COptex代碼。原代碼下載

Figure 2: COptex

Optex.h

/******************************************************************************

Module name: Optex.h

Written by: Jeffrey Richter

Purpose: Defines the COptex (optimized mutex) synchronization object

******************************************************************************/

#pragma once

///////////////////////////////////////////////////////////////////////////////

class COptex {

public:

COptex(LPCSTR pszName, DWORD dwSpinCount = 4000);

COptex(LPCWSTR pszName, DWORD dwSpinCount = 4000);

~COptex();

void SetSpinCount(DWORD dwSpinCount);

void Enter();

BOOL TryEnter();

void Leave();

private:

typedef struct {

DWORD m_dwSpinCount;

long m_lLockCount;

DWORD m_dwThreadId;

long m_lRecurseCount;

} SHAREDINFO, *PSHAREDINFO;

BOOL m_fUniprocessorHost;

HANDLE m_hevt;

HANDLE m_hfm;

PSHAREDINFO m_pSharedInfo;

private:

BOOL CommonConstructor(PVOID pszName, BOOL fUnicode, DWORD dwSpinCount);

};

///////////////////////////////////////////////////////////////////////////////

inline COptex::COptex(LPCSTR pszName, DWORD dwSpinCount) {

CommonConstructor((PVOID) pszName, FALSE, dwSpinCount);

}

///////////////////////////////////////////////////////////////////////////////

inline COptex::COptex(LPCWSTR pszName, DWORD dwSpinCount) {

CommonConstructor((PVOID) pszName, TRUE, dwSpinCount);

}

Optex.cpp

/******************************************************************************

Module name: Optex.cpp

Written by: Jeffrey Richter

Purpose: Implements the COptex (optimized mutex) synchronization object

******************************************************************************/

#include <windows.h>

#include "Optex.h"

///////////////////////////////////////////////////////////////////////////////

BOOL COptex::CommonConstructor(PVOID pszName, BOOL fUnicode, DWORD dwSpinCount) 

{

m_hevt = m_hfm = NULL;

m_pSharedInfo = NULL;

SYSTEM_INFO sinf;

GetSystemInfo(&sinf);

m_fUniprocessorHost = (sinf.dwNumberOfProcessors == 1);

char szNameA[100];

if (fUnicode) { // Convert Unicode name to ANSI

wsprintfA(szNameA, "%S", pszName);

pszName = (PVOID) szNameA;

}

char sz[100];

wsprintfA(sz, "JMR_Optex_Event_%s", pszName);

m_hevt = CreateEventA(NULL, FALSE, FALSE, sz);

if (m_hevt != NULL) {

wsprintfA(sz, "JMR_Optex_MMF_%s", pszName);

m_hfm = CreateFileMappingA(NULL, NULL, PAGE_READWRITE, 0, sizeof(*m_pSharedInfo), sz);

if (m_hfm != NULL) {

m_pSharedInfo = (PSHAREDINFO) MapViewOfFile(m_hfm, FILE_MAP_WRITE, 

0, 0, 0);

// Note: SHAREDINFO''s m_lLockCount, m_dwThreadId, and m_lRecurseCount

// members need to be initialized to 0. Fortunately, a new pagefile 

// MMF sets all of its data to 0 when created. This saves us from 

// some thread synchronization work.

if (m_pSharedInfo != NULL) 

SetSpinCount(dwSpinCount);

}

}

return((m_hevt != NULL) && (m_hfm != NULL) && (m_pSharedInfo != NULL));

}

///////////////////////////////////////////////////////////////////////////////

COptex::~COptex() {

#ifdef _DEBUG

if (m_pSharedInfo->m_dwThreadId != 0) DebugBreak();

#endif

UnmapViewOfFile(m_pSharedInfo);

CloseHandle(m_hfm);

CloseHandle(m_hevt);

}

///////////////////////////////////////////////////////////////////////////////

void COptex::SetSpinCount(DWORD dwSpinCount) {

if (!m_fUniprocessorHost)

InterlockedExchange((PLONG) &m_pSharedInfo->m_dwSpinCount, dwSpinCount);

}

///////////////////////////////////////////////////////////////////////////////

void COptex::Enter() {

// Spin, trying to get the Optex

if (TryEnter()) return;

DWORD dwThreadId = GetCurrentThreadId(); // The calling thread''s ID

if (InterlockedIncrement(&m_pSharedInfo->m_lLockCount) == 1) {

// Optex is unowned, let this thread own it once

InterlockedExchange((PLONG) &m_pSharedInfo->m_dwThreadId, dwThreadId);

m_pSharedInfo->m_lRecurseCount = 1;

} else {

// Optex is owned by a thread

if (m_pSharedInfo->m_dwThreadId == dwThreadId) {

// Optex is owned by this thread, own it again

m_pSharedInfo->m_lRecurseCount++;

} else {

// Optex is owned by another thread

// Wait for the Owning thread to release the Optex

WaitForSingleObject(m_hevt, INFINITE);

// We got ownership of the Optex

InterlockedExchange((PLONG) &m_pSharedInfo->m_dwThreadId, 

dwThreadId); // We own it now

m_pSharedInfo->m_lRecurseCount = 1; // We own it once

}

}

}

///////////////////////////////////////////////////////////////////////////////

 

BOOL COptex::TryEnter() {

DWORD dwThreadId = GetCurrentThreadId(); // The calling thread''s ID

// If the lock count is zero, the Optex is unowned and

// this thread can become the owner of it now.

BOOL fThisThreadOwnsTheOptex = FALSE;

DWORD dwSpinCount = m_pSharedInfo->m_dwSpinCount;

do {

fThisThreadOwnsTheOptex = (0 == (DWORD) 

InterlockedCompareExchange((PVOID*) &m_pSharedInfo->m_lLockCount, 

(PVOID) 1, (PVOID) 0)); 

if (fThisThreadOwnsTheOptex) {

// We now own the Optex

InterlockedExchange((PLONG) &m_pSharedInfo->m_dwThreadId, 

dwThreadId); // We own it

m_pSharedInfo->m_lRecurseCount = 1; // We own it once

} else {

// Some thread owns the Optex

if (m_pSharedInfo->m_dwThreadId == dwThreadId) {

// We already own the Optex

InterlockedIncrement(&m_pSharedInfo->m_lLockCount);

m_pSharedInfo->m_lRecurseCount++; // We own it again

fThisThreadOwnsTheOptex = TRUE; // Return that we own the Optex

}

}

} while (!fThisThreadOwnsTheOptex && (dwSpinCount-- > 0));

// Return whether or not this thread owns the Optex

return(fThisThreadOwnsTheOptex);

}

 

///////////////////////////////////////////////////////////////////////////////

 

void COptex::Leave() {

#ifdef _DEBUG

if (m_pSharedInfo->m_dwThreadId != GetCurrentThreadId()) 

DebugBreak();

#endif

if (--m_pSharedInfo->m_lRecurseCount > 0) {

// We still own the Optex

InterlockedDecrement(&m_pSharedInfo->m_lLockCount);

} else {

// We don''t own the Optex

InterlockedExchange((PLONG) &m_pSharedInfo->m_dwThreadId, 0);

if (InterlockedDecrement(&m_pSharedInfo->m_lLockCount) > 0) {

// Other threads are waiting, wake one of them

SetEvent(m_hevt);

}

}

}

 

///////////////////////////////// End of File /////////////////////////////////

使用這個COptex是很簡單的事情,只要構(gòu)造用下面這兩種構(gòu)造函數(shù)一個C++類的實例即可.

構(gòu)造函數(shù)

COptex(LPCSTR pszName, DWORD dwSpinCount = 4000);

COptex(LPCWSTR pszName, DWORD dwSpinCount = 4000);

他們都調(diào)用了

BOOL CommonConstructor(PVOID pszName, BOOL fUnicode, DWORD dwSpinCount);

構(gòu)造一個COptex對象必須給它一個字符串型的名字,在突破進程邊界的時候這是必須的,只有這個名字能提供共享訪問.構(gòu)造函數(shù)支持ANSI或Unicode的名字。

當(dāng)另外一個進程使用相同的名字構(gòu)造一個COptex對象,構(gòu)造函數(shù)如何發(fā)現(xiàn)已經(jīng)存在的COptex對象?在CommonConstructor代碼中用CreateEvent嘗試創(chuàng)建一個命名Event對象,如果這個名字的Event對象已經(jīng)存在,那么,得到該對象的句柄,并且GetLastError可以得到ERROR_ALREADY_EXISTS.如果不存在則創(chuàng)建一個.如果創(chuàng)建失敗,則得到的句柄為NULL.

同樣的,可以得到一個共享的內(nèi)存映象文件的句柄.

構(gòu)造成功后,在需要同步時,根據(jù)情況簡單的執(zhí)行相應(yīng)的進程間同步操作。構(gòu)造函數(shù)的第二個參數(shù)用來指定Spin計數(shù),默認是4000(這是操作系統(tǒng)序列化堆Heap的函數(shù)所使用的數(shù)量.操作系統(tǒng)在分配和釋放內(nèi)存的時候,要序列化進程的堆,這時也要用到臨界段)

COptex類的其他函數(shù)和Win32函數(shù)是一一對應(yīng)的.熟悉同步對象的程序員應(yīng)該很容易理解.

COptex是如何工作的呢?實際上,一個COptex包含兩個數(shù)據(jù)塊(Data blocks):一個本地的,私有的;另一個是全局的,共享的.一個COptex對象構(gòu)造之后,本地數(shù)據(jù)塊包含了COptex的成員變量:m_hevt變量初始化為一個命名事件對象句柄;m_hfm變量初始化為一個內(nèi)存映象文件對象句柄.既然這些句柄代表的對象是命名的,那么,他們可以在進程間共享。注意,是"對象"可以共享,而不是"對象的句柄".每個進程內(nèi)的COptex對象都必須保持這些句柄在本進程內(nèi)的值.

m_pShareInf成員指向一個內(nèi)存映象文件,全局數(shù)據(jù)塊在這個內(nèi)存映象文件里,以指定的共享名存在. SHAREDINFO結(jié)構(gòu)是內(nèi)存映象數(shù)據(jù)的組織方式,該結(jié)構(gòu)在COptex類里定義,和CRITCIAL_SECTION的結(jié)構(gòu)非常相似.

typedef struct {

DWORD m_dwSpinCount;

long m_lLockCount;

DWORD m_dwThreadId;

long m_lRecurseCount;report-2001-03-07.htm

} SHAREDINFO, *PSHAREDINFO;

m_dwSpinCount : spin計數(shù)

m_lLockCount : 鎖定計數(shù)

m_dwThreadID : 擁有該臨界段的線程ID

m_lRecurseCount:本線程擁有該臨界段的計數(shù)

好了,仔細看看代碼吧,大師風(fēng)范呀.注意一下在進行同步時,關(guān)于是否同一線程,關(guān)于LockCount的值的一系列的判斷,以及InterLockedXXX系列函數(shù)的使用,具體用法查MSDN.

bear最喜歡這樣的代碼了,簡單明了,思路清晰,原理超值,看完了只想大喝一聲"又學(xué)一招,爽!"

bear也寫累了 ,收工:).

2001.3.2 

隨意轉(zhuǎn)載,只要不去掉Jeffrey的名字,還有bear的:D

翻譯有錯,請找vcbear@sina.com或留言,不懂Win32編程看下面:

Have a question about programming in Win32? Contact Jeffrey Richter at http://www.jeffreyrichter.com/

From the January 1998 issue of Microsoft Systems Journal. 

<!--article end-->

?? 快捷鍵說明

復(fù)制代碼 Ctrl + C
搜索代碼 Ctrl + F
全屏模式 F11
切換主題 Ctrl + Shift + D
顯示快捷鍵 ?
增大字號 Ctrl + =
減小字號 Ctrl + -
亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
日韩丝袜美女视频| 日韩精品视频网站| 国产日韩欧美高清在线| 欧美成人vps| 久久影视一区二区| 久久精品视频一区二区| 国产婷婷精品av在线| 欧美高清在线精品一区| 日韩一区在线播放| 亚洲精品亚洲人成人网 | 亚洲人成7777| 亚洲免费伊人电影| 亚洲地区一二三色| 毛片一区二区三区| 国内精品伊人久久久久av影院| 黄色成人免费在线| 成人av在线观| 欧美日韩中文字幕精品| 欧美一区二区精品在线| 精品国产乱码久久久久久影片| 精品国产乱码久久久久久夜甘婷婷 | 亚洲视频在线一区二区| 亚洲一区二区三区激情| 日本 国产 欧美色综合| 国产成人自拍高清视频在线免费播放| 国产精品中文字幕一区二区三区| 懂色中文一区二区在线播放| 91免费在线播放| 欧美乱妇一区二区三区不卡视频| 91精品国产乱| 国产精品网站导航| 亚洲综合色区另类av| 欧美aaa在线| 波多野结衣一区二区三区| 在线看日本不卡| 精品国产1区二区| 亚洲女人的天堂| 久久精品国产**网站演员| 成人中文字幕在线| 欧美日韩在线播放| 国产丝袜在线精品| 午夜精品久久久久久久久| 久久国产精品一区二区| 97久久久精品综合88久久| 欧美福利视频导航| 欧美激情一区三区| 视频精品一区二区| 9l国产精品久久久久麻豆| 91麻豆精品国产综合久久久久久| 国产精品美女一区二区三区| 视频一区中文字幕国产| 处破女av一区二区| 日韩午夜激情免费电影| 亚洲日本va在线观看| 老司机精品视频导航| 91网站最新网址| 久久综合色鬼综合色| 亚洲一二三四在线观看| 国产电影一区二区三区| 91精品国产aⅴ一区二区| 综合久久国产九一剧情麻豆| 久久国产精品无码网站| 精品视频1区2区| 国产精品久久久久久久蜜臀| 免费欧美在线视频| 欧美色精品天天在线观看视频| 欧美经典一区二区| 麻豆国产欧美日韩综合精品二区| 一本一本大道香蕉久在线精品| 亚洲精品一区二区三区影院 | 久久97超碰色| 欧美欧美午夜aⅴ在线观看| 中文字幕亚洲在| 国产一区二区三区免费在线观看 | 午夜久久久久久久久| 91麻豆高清视频| 国产色产综合色产在线视频 | 在线不卡中文字幕播放| 亚洲人成7777| 99久久精品免费观看| 国产日韩欧美高清| 国产麻豆成人精品| 久久综合五月天婷婷伊人| 日本视频一区二区三区| 欧美日韩另类国产亚洲欧美一级| 亚洲日韩欧美一区二区在线| 国产jizzjizz一区二区| 久久在线观看免费| 国产一区二区美女诱惑| 欧美mv和日韩mv的网站| 日韩国产精品久久| 欧美日精品一区视频| 亚洲国产一区在线观看| 色悠悠亚洲一区二区| 亚洲日本在线天堂| 色综合天天综合网天天看片| 国产精品入口麻豆原神| 成人黄色一级视频| 国产精品久久久久久亚洲毛片 | 91.com视频| 日韩高清一级片| 日韩一级黄色大片| 麻豆成人免费电影| 26uuu欧美| 国产成人免费av在线| 中文一区一区三区高中清不卡| 国产电影一区二区三区| 国产精品久久久久一区二区三区| 成人av电影在线网| 亚洲视频免费在线| 在线中文字幕不卡| 亚洲成人一二三| 日韩一区二区视频在线观看| 捆绑调教美女网站视频一区| 精品对白一区国产伦| 国产高清不卡一区| 亚洲三级理论片| 欧美网站大全在线观看| 免费在线看成人av| 久久久久综合网| 99vv1com这只有精品| 亚洲国产一区在线观看| 日韩欧美视频一区| 国产精品18久久久久久久久久久久 | eeuss鲁片一区二区三区| 亚洲人成人一区二区在线观看| 欧美羞羞免费网站| 免费黄网站欧美| 国产精品三级久久久久三级| 91黄色激情网站| 欧美aaaaa成人免费观看视频| 久久久久97国产精华液好用吗| 成年人网站91| 亚洲五月六月丁香激情| 精品国产一区二区三区忘忧草 | 欧美视频日韩视频| 国产在线播放一区二区三区| 亚洲天堂精品在线观看| 欧美一区二区三区啪啪| 粉嫩av一区二区三区| 亚洲成精国产精品女| 国产欧美一区二区三区在线看蜜臀 | 亚洲高清免费在线| 久久久一区二区三区捆绑**| 一本大道久久精品懂色aⅴ| 日韩精品一区第一页| 国产精品美女www爽爽爽| 欧美剧情电影在线观看完整版免费励志电影| 免费观看一级欧美片| 一区二区中文字幕在线| 在线成人小视频| av一区二区久久| 日本成人中文字幕在线视频| 中文字幕在线不卡| 日韩天堂在线观看| 在线观看一区不卡| 国产剧情一区在线| 亚欧色一区w666天堂| 中文字幕在线观看不卡视频| 日韩一级免费一区| 欧美最猛黑人xxxxx猛交| 韩国三级中文字幕hd久久精品| 亚洲一区二区欧美| 国产精品亲子乱子伦xxxx裸| 91.xcao| 欧美自拍偷拍一区| 国产99一区视频免费 | 欧美曰成人黄网| 懂色av一区二区三区蜜臀| 美女一区二区视频| 亚洲主播在线观看| 中文字幕亚洲欧美在线不卡| 久久午夜电影网| 欧美一区二区私人影院日本| 色综合色综合色综合| 成人免费毛片片v| 韩国欧美国产一区| 日韩精品成人一区二区在线| 玉足女爽爽91| 自拍偷拍国产精品| 国产亚洲欧美一区在线观看| 日韩欧美国产综合一区| 777久久久精品| 欧美日韩一本到| 91久久精品网| hitomi一区二区三区精品| 国产超碰在线一区| 国产精品一线二线三线| 久久精品72免费观看| 人人爽香蕉精品| 日本91福利区| 天天做天天摸天天爽国产一区| 亚洲尤物在线视频观看| 亚洲三级电影网站| 亚洲女同一区二区| 综合色天天鬼久久鬼色| 亚洲三级电影全部在线观看高清| 中文字幕在线免费不卡| √…a在线天堂一区| 国产精品久久久99|