2009-03-11 34 views
6

コードセクションに簡単な「一度に1つの」ロックが必要です。シンプルなスレッド同期

void func() 
{ 
    // locking/mutex statement goes here 
    operation1(); 
    operation2(); 
    // corresponding unlock goes here 
    operation3(); 
} 

私はoperation1operation2は常に「一緒に」実行することを確認する必要があります。複数のスレッドから実行できる機能funcを考えてみましょう。 C#では、これら2つの呼び出しの回りに単純なlockブロックを使用します。 C++/Win32/MFCに相当するものは何ですか?

おそらく何らかの種類のMutex

答えて

19

重要なセクションが機能します(これらのミューテックスは軽量です)。InitializeCriticalSection、EnterCriticalSection、LeaveCriticalSection、およびDeleteCriticalSectionは、MSDNで検索する関数です。

void func() 
{ 
    // cs previously initialized via InitializeCriticalSection 
    EnterCriticalSection(&cs); 
    operation1(); 
    operation2(); 
    LeaveCriticalSection(&cs); 
    operation3();} 
} 

EDIT:クリティカルセクションは、主にユーザ・モード・プリミティブであるので クリティカルセクションがミューテックスより速い - 競合のない取得(通常は一般的な場合)カーネルにないシステムコールが存在しない場合で、かつ取得がかかり何十回ものオーダーである。カーネルスイッチは、より高価です(数百サイクル程度)。クリティカルセクションがカーネルに呼び出される唯一の時間は、カーネルプリミティブ(ミューテックスまたはイベントのいずれか)で待機することです。ミューテックスを獲得するには、常にカーネルへの呼び出しが必要であり、そのためには何倍も遅くなります。 しかし、クリティカルセクションは、1つのプロセスでリソースを同期するためにのみ使用できます。複数のプロセス間で同期させるためには、ミューテックスが必要です。

+0

CriticalSectionsが内部的にミューテックスを使用していることを知る限り、パフォーマンス上の利点はありません。 –

+0

そして、例外安全のためにクラスにcsをラップすることができます。 RAIIを参照してください。 – Reunanen

+0

(質問はC++に関するものです) – Reunanen

2

あなたはこれを試すことができます。

void func() 
{ 
    // See answer by Sasha on how to create the mutex 
    WaitForSingleObject (mutex, INFINITE); 
    operation1(); 
    operation2(); 
    ReleaseMutex(mutex); 
    operation3(); 
} 
+0

WaitForSingleObjectが遅いです。 CriticalSectionsは回転カウントを取ることができ、しばらくの間回転してからWaitForSingleObjectに落ちます。 http://msdn.microsoft.com/en-us/library/ms683476(VS.85).aspx InitializeCriticalSectionAndSpinCount関数 –

6

最善の方法は、EnterCriticalSectionとLeaveCriticalSectionを使用し、クリティカルセクションを使用することです。ちょっとした部分は、InitializeCriticalSectionでクリティカルセクションを最初に初期化する必要があることです。このコードがクラス内にある場合は、初期化をコンストラクタに、CRITICAL_SECTIONデータ構造体をクラスのメンバとして配置します。コードがクラスに含まれていない場合は、一度グローバル化されたものを使用して、それが一度初期化されていることを確認する必要があります。

6
  1. 使用してMFC:

    1. が同期オブジェクトを定義します。

      1.1異なるプロセスに属する複数のスレッドが func()を入力した場合は、CMutexを使用します。

      1.2。同じプロセスの複数のスレッドがfunc()に入る場合は、 CCriticalSectionを使用します。

    2. 同期オブジェクトの使用を簡単にするために、CSingleLockを使用できます。

は、クリティカルセクションに、我々が定義したとしましょう

CCriticalSection m_CriticalSection; 
    void func() 
    { 
     // locking/mutex statement goes here 
     CSingleLock aLock(&m_CriticalSection, **TRUE**); 
     // TRUE indicates that Lock aquired during aLock creation. 
     // if FALSE used then use aLock.Lock() for locking. 

     operation1(); 
     operation2(); 
      // corresponding unlock goes here 
      aLock.Unlock(); 
     operation3(); 
    } 

EDIT:MSDNからVC++の記事を参照してください:Multithreading with C++ and MFC ClassesMultithreading: How to Use the Synchronization Classes

25

上記Michael solutionを修正します。

マイケルソリューションはCアプリケーションに最適です。しかし、C++で使用された場合、このスタイルは例外の可能性のために推奨されません。 operation1またはoperation2で例外が発生した場合、クリティカルセクションは正しく残されず、他のすべてのスレッドは待機をブロックします。

// Perfect solutiuon for C applications 
void func() 
{ 
    // cs previously initialized via InitializeCriticalSection 
    EnterCriticalSection(&cs); 
    operation1(); 
    operation2(); 
    LeaveCriticalSection(&cs); 
    operation3();} 
} 

// A better solution for C++ 
class Locker 
{ 
    public: 
    Locker(CSType& cs): m_cs(cs) 
    { 
     EnterCriticalSection(&m_cs); 
    } 
    ~Locker() 
    { 
     LeaveCriticalSection(&m_cs); 
    } 
    private: 
     CSType& m_cs; 
} 
void func() 
{ 
    // cs previously initialized via InitializeCriticalSection 
    { 
     Locker lock(cs); 
     operation1(); 
     operation2(); 
    } 
    operation3(); 
} 
+0

+1 RAIIベストプラクティスを参照してください。 – deepdive

+0

プログラミングの技術。非常にエレガント。クリティカルセクションブロックを簡単に区別し、間違いを起こしにくい:-) – StanE

+0

ベストアンサー:) – Mak