2017-09-02 84 views
4

我已經寫了一個簡單的單例應用程序。與信號量的Threadsafe單例問題

以下是我的樣本主類

// 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(); 
}; 

的問題是反的最終值是從來沒有100有人可以解釋我爲什麼,什麼是我做wrong.I我無法理解的問題。當我在創建每個線程之前在主體中引入睡眠時,它可以正常工作。

+0

爲什麼不使用C++自己的線程功能而不是Win32? –

+0

@prv不要編輯帶有答案的問題。在回答中發佈更正的代碼,而不是問題。如果有人解決你的問題,並給他們一個複選標記,並且他們幫助upvote。允許自我回答;編輯問題以使現有答案沒有意義。 – Yakk

回答

5

的問題是,調用WaitForMultipleObjects句柄MAXIMUM_WAIT_OBJECTS了其中,至少在Visual Studio 2017年,是64

通知您到WaitForMultipleObjects呼叫如何加入線程返回WAIT_FAILED

爲了等待一個應該多個對象,according to the documentation

要等待超過MAXIMUM_WAIT_OBJECTS處理更多,請使用下列方法之一:

  • 創建一個線程等待MAXIMUM_WAIT_OBJECTS處理,然後等待該線程加上其他句柄。使用這種技術將句柄分成MAXIMUM_WAIT_OBJECTS組。
  • 調用RegisterWaitForSingleObject在每個句柄上等待。線程池中的等待線程等待MAXIMUM_WAIT_OBJECTS註冊對象,並在對象發出信號或超時間隔到期後分配工作線程。
+0

你是完全正確的。非常感謝現在我得到了什麼問題。再次感謝 –

2

你不需要編寫所有的代碼。實現線程單身的最簡單方法是使用斯科特·邁爾的單成語:

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; 
    } 
}; 

更簡單的方法是使用一個std::atomic<int>型爲counter成員變量。那麼互斥鎖和鎖守可以完全省略。

+0

我相信寫單身是這個練習的一部分。 – orhtej2

+0

感謝您的回覆。問題不在於單一噸。問題是我在單身人士的櫃檯。我期待在程序執行結束時,計數器的值與我在main中的線程數相同,但事實並非如此。這是我無法理解的。 –

+0

@PrV好吧,我更願意回答你在問題標題中的含義。無論如何,我所展示的代碼是在C++中實現(線程安全)Singleton的慣用方式。 – user0042