秒殺マルチスレッド第8編古典スレッド同期信号量Semaphore


本編を読む前に、以下の姉妹編を読むことをお勧めします.
『秒殺マルチスレッド第4編古典的なマルチスレッド同期問題』
《秒殺マルチスレッド第五篇経典スレッド同期キーセグメントCS》
《秒殺マルチスレッド第六篇経典スレッド同期イベントEvent》
《秒殺マルチスレッド第七篇経典スレッド同期反発量Mutex》
 
従来のスレッド同期問題におけるキーセグメントCS、イベントEvent、反発量Mutexの使用について説明した.本編では,この問題を信号量Semaphoreで解決することを紹介する.
まず、信号量の使い方を見てみましょう.信号量Semaphoreにはよく3つの関数があり、使いやすいです.以下に、これらの関数のプロトタイプと使用説明を示します.
最初のCreateSemaphore
関数機能:信号量の作成
関数のプロトタイプ:
HANDLE CreateSemaphore(
  LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
  LONG lInitialCount,
  LONG lMaximumCount,
  LPCTSTR lpName
);
関数の説明:
最初のパラメータはセキュリティ制御を表し、一般的にNULLに直接入力されます.
2番目のパラメータは、初期リソース数を表します.
3番目のパラメータは、最大同時数量を表します.
4番目のパラメータは信号量の名前を表し、NULLは匿名信号量を表す.
 
2番目のOpenSemaphore
関数機能:オープン信号量
関数のプロトタイプ:
HANDLE OpenSemaphore(
  DWORD dwDesiredAccess,
  BOOL bInheritHandle,
  LPCTSTR lpName
);
関数の説明:
最初のパラメータはアクセス権限を表し、一般的にSEMAPHOREに転送されます.ALL_ACCESS.詳細については、MSDNドキュメントを参照してください.
2番目のパラメータは信号量ハンドル継承性を表し、一般的にTRUEに伝達すればよい.
3番目のパラメータは名前を表し、異なるプロセスの各スレッドは名前によって同じ信号量にアクセスできることを保証します.
 
3番目のReleaseSemaphore
関数機能:増分信号量の現在のリソースカウント
関数のプロトタイプ:
BOOL ReleaseSemaphore(
  HANDLE hSemaphore,
  LONG lReleaseCount,  
  LPLONG lpPreviousCount 
);
関数の説明:
最初のパラメータは信号量のハンドルです.
2番目のパラメータは、0より大きく、最大リソース数を超えない数の増加を示します.
3番目のパラメータは、以前のリソースカウントを送信するために使用することができ、NULLに設定すると、送信する必要がないことを示します.
 
注意:現在のリソース数が0より大きい場合は、信号量がトリガされていることを示し、0に等しい場合は、リソースが消費されているため、信号量が最終トリガされていることを示します.信号量に対して待機関数を呼び出すと、待機関数は信号量の現在のリソースカウントをチェックし、0(すなわち信号量がトリガ状態)より大きい場合は、1を減算して呼び出しスレッドを実行させます.1つのスレッドは、信号量を低減するために待機関数を複数回呼び出すことができる. 
 
最後の信号量のクリーンアップと破棄
信号量はカーネルオブジェクトであるため、CloseHandle()を使用するとクリーンアップと破棄が完了します.
 
古典的なマルチスレッド問題で信号量とキーセグメントを設定します.主スレッドとサブスレッドの同期を信号量で処理し,各サブスレッド間の反発をキーセグメントで処理する.詳細は、コードを参照してください.
#include 
#include 
#include 
long g_nNum;
unsigned int __stdcall Fun(void *pPM);
const int THREAD_NUM = 10;
//       
HANDLE            g_hThreadParameter;
CRITICAL_SECTION  g_csThreadCode;
int main()
{
	printf("               Semaphore
"); printf(" -- by MoreWindows( http://blog.csdn.net/MoreWindows ) --

"); // g_hThreadParameter = CreateSemaphore(NULL, 0, 1, NULL);// 0 , 1 InitializeCriticalSection(&g_csThreadCode); HANDLE handle[THREAD_NUM]; g_nNum = 0; int i = 0; while (i < THREAD_NUM) { handle[i] = (HANDLE)_beginthreadex(NULL, 0, Fun, &i, 0, NULL); WaitForSingleObject(g_hThreadParameter, INFINITE);// >0 ++i; } WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE); // DeleteCriticalSection(&g_csThreadCode); CloseHandle(g_hThreadParameter); for (i = 0; i < THREAD_NUM; i++) CloseHandle(handle[i]); return 0; } unsigned int __stdcall Fun(void *pPM) { int nThreadNum = *(int *)pPM; ReleaseSemaphore(g_hThreadParameter, 1, NULL);// ++ Sleep(50);//some work should to do EnterCriticalSection(&g_csThreadCode); ++g_nNum; Sleep(0);//some work should to do printf(" %d %d
", nThreadNum, g_nNum); LeaveCriticalSection(&g_csThreadCode); return 0; }

次のように動作します.
信号量もスレッド間の同期問題を解決できることがわかる.
 
信号量は、リソースの現在の残量を計算し、現在の残量をゼロと比較して信号量がトリガ状態または非トリガ状態であることを決定することができるため、信号量の応用範囲はかなり広い.このシリーズの「秒殺マルチスレッド第10編生産者消費者問題」は、スレッド同期問題を解決するために再び使用されます.参照してください.
 
これで、クラシックスレッド同期問題はすべて終了し、次の「秒殺マルチスレッド第9編クラシックマルチスレッド同期問題総括」では、各知識点を整理するためにまとめられます.
 
転載は出典、原文住所を明記してください.http://blog.csdn.net/morewindows/article/details/7481609
もし本文があなたに役に立つと思ったら、「トップ」をクリックして支持してください.あなたの支持は私の書く最大の動力です.ありがとうございます.