2017-09-02 33 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