2017-09-02 5 views
4

シンプルシングルトンアプリケーションを作成しました。スレッドセーフセマンティヴ(セマフォ付き)

次は、これは私のシングルトンの実装クラスである

// ThreadsafeSingletonUsingSemaphore.cpp : Defines the entry point for the console application. 
// 

#include "stdafx.h" 
#include <iostream> 
#include <conio.h> 
#include "MySingleton.h" 
using namespace std; 

int i =0; 
#define THREADCOUNT 100 
DWORD WINAPI ThreadProc(LPVOID lParam); 
HANDLE g_semaphore = NULL; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    g_semaphore = CreateSemaphore(NULL,1,1,_T("TreadOne")); 
    HANDLE hThread[THREADCOUNT]; 
    DWORD aThreadID; 

    for(int iCount = 0; iCount < THREADCOUNT ; iCount++) 
    { 
     hThread[iCount] = CreateThread(NULL, 0, ThreadProc, 0,0, &aThreadID); 
     if(hThread[iCount] == NULL) 
     { 
      cout<<"CreateThread error: %d" << GetLastError() << endl; 
      return 1; 
     } 
    } 

    WaitForMultipleObjects(THREADCOUNT, hThread, TRUE, INFINITE); 

    // Close thread and semaphore handles 
    for(int i=0; i < THREADCOUNT; i++) 
     CloseHandle(hThread[i]); 

    cout << MySingleton::getInstance().getCounter() << endl ; 

    CloseHandle(g_semaphore); 
    _getch(); 
    return 0; 
} 

DWORD WINAPI ThreadProc(LPVOID lpParam) 
{ 
    //DWORD result = WaitForSingleObject(g_semaphore,INFINITE); 
    //if(WAIT_OBJECT_0 == result) 
     MySingleton::getInstance().incrementCouner(); 
    //ReleaseSemaphore(g_semaphore,1, NULL); 
    return TRUE; 
} 

私のサンプルのメインクラスです。

#include "StdAfx.h" 
#include "MySingleton.h" 

MySingleton* MySingleton::m_instance = NULL; 
HANDLE MySingleton::m_hSem = CreateSemaphore(NULL, 1, 1, _T("MySingleton")); 
HANDLE MySingleton::m_One = CreateSemaphore(NULL, 1, 1, _T("MyOne")); 

MySingleton::MySingleton(void) : m_counter(0) 
{ 
} 

MySingleton::~MySingleton(void) 
{ 
    cout << "destructor" << endl; 
    CloseHandle(m_hSem); 
    CloseHandle(m_One); 
} 

MySingleton& MySingleton::getInstance() 
{ 
    DWORD result = WaitForSingleObject(m_hSem, INFINITE); 

    if(WAIT_OBJECT_0 == result) 
    { 
     if(m_instance == NULL) 
     { 
      cout << "creating" << endl; 
      m_instance = new MySingleton(); 
     } 
    } 
    ReleaseSemaphore(m_hSem,1,NULL); 
    return *m_instance; 
} 

void MySingleton::setCouner(int iCount_in) 
{ 
    m_counter = iCount_in; 
} 
int MySingleton::getCounter() 
{ 
    return m_counter; 
} 

void MySingleton::incrementCouner() 
{ 
    DWORD result = WaitForSingleObject(m_One, INFINITE); 
    if(WAIT_OBJECT_0 == result) 
     m_counter++; 
    ReleaseSemaphore(m_One,1,NULL); 
} 

これは私の.hクラスです。

#pragma once 
#include <windows.h> 
#include <iostream> 
#include <conio.h> 
using namespace std; 

class MySingleton 
{ 
private: 
    static HANDLE m_hSem, m_One; 
    HANDLE m_hCountSem; 
    static MySingleton* m_instance; 
    int m_counter; 
    MySingleton(); 
    MySingleton(const MySingleton& obj_in); 
    MySingleton& operator=(const MySingleton& obj_in); 
public: 
    ~MySingleton(void); 

    static MySingleton& getInstance(); 
    void setCouner(int iCount_in); 
    int getCounter(); 

    void incrementCouner(); 
}; 

問題は、カウンタの最終値は、誰かが私に理由を説明し、私はwrong.Iをやっているということであることは問題を理解することはできませんよてくださいすることができ100になることはありませんです。各スレッドを作成する前にメインでスリープ状態を導入すると、正常に動作します。

+0

なぜWin32ではなくC++独自のスレッド機能を使用しないのですか? –

+0

@prv質問を回答で編集しないでください。質問にではなく、回答を修正したコードを投稿してください。誰かがあなたの問題upvoteを解決し、それらにチェックマークを付けて、彼らがupvoteを助けるかどうか。自己回答は許可されます。既存の回答をするための質問を編集することは意味をなさない。 – Yakk

答えて

5

問題がWaitForMultipleObjectsへの呼び出しが、少なくともVisual Studioの2017年に、WaitForMultipleObjectsへのお電話は、スレッドに参加するにはどのように64

お知らせがWAIT_FAILEDを返すである、MAXIMUM_WAIT_OBJECTSまで扱うということです。以下のいずれかの方法を使用し、MAXIMUM_WAIT_OBJECTSハンドルよりも上の待つに

:1がすべき複数のオブジェクト、according to the documentationを待つために

  • MAXIMUM_WAIT_OBJECTSで待機するスレッドを作成します。そのスレッドと他のハンドルを待ちます。このテクニックを使用して、ハンドルをMAXIMUM_WAIT_OBJECTSのグループに分割します。
  • 呼び出しごとに、ハンドルごとに待機するWaitForSingleObject。スレッドプールからの待機スレッドはMAXIMUM_WAIT_OBJECTSの登録済みオブジェクトを待機し、オブジェクトが通知された後、またはタイムアウト間隔が経過した後にワーカースレッドを割り当てます。
+0

あなたは完全に正しいです。ありがとうございました今、私は問題があります。もう一度ありがとう –

2

すべてのコードを記述する必要はありません。さらに簡単な方法は、counterメンバ変数のためstd::atomic<int>タイプを使用することです

class Singleton { 
    int counter; 
    mutable std::mutex counter_guard; 
    Singleton() {} 
public: 
    Singleton(const Singleton&) = delete; 
    Singleton(Singleton&&) = delete; 
    Singleton& operator=(const Singleton&) = delete; 
    Singleton& operator=(Singleton&&) = delete; 

    static Singleton& instance() { 
     static Singleton theInstance; 
     return theInstance; 
    } 

    void setCounter(int newVal) { 
     std::unique_lock<std::mutex> lock(counter_guard); 
     counter = newVal; 
    } 
    void incrementCounter() { 
     std::unique_lock<std::mutex> lock(counter_guard); 
     ++counter; 
    } 
    int getCounter() const { 
     std::unique_lock<std::mutex> lock(counter_guard); 
     return counter; 
    } 
}; 

:スレッドセーフシングルトンを実装するための最も簡単な方法は、スコット・マイヤーのシングルトンのイディオムを使用することです。次に、ミューテックスとロックガードをまったく省略することができます。

+0

私はシングルトンを書くことがこの運動の一部であると信じています。 – orhtej2

+0

ご返信ありがとうございます。問題は1トンではない。問題は、私がシングルトンで持っているカウンターです。私はプログラムの実行の終わりに期待していた、カウンタの値はメインのスレッド数と同じになりますが、そうではありません。それは私が理解できないものです。 –

+0

@PrVまあ、私はあなたの質問のタイトルに書いたものにもっと答えを出すつもりでした。とにかく、私が示すコードは、(スレッドセーフな)シングルトンをC++で実装する慣用的な方法です。 – user0042

関連する問題