issue with Threadsafe singleton with semaphore

巧了我就是萌 提交于 2019-12-01 04:32:38

问题


I have written a simple singleton application.

The following is my sample main class

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

This is my singleton implementation class.

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

This is my .h class.

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

The problem is the final value of counter is never 100. can someone please explain me why and what is that i am doing wrong.I am not able to understand the problem. When I introduce sleep in the main before creating each thread, it works fine.


回答1:


The problem is that call to WaitForMultipleObjects handles up to MAXIMUM_WAIT_OBJECTS which, at least in Visual Studio 2017, is 64.

Notice how your call to WaitForMultipleObjects to join threads returns WAIT_FAILED.

In order to wait for more objects one should, according to the documentation:

To wait on more than MAXIMUM_WAIT_OBJECTS handles, use one of the following methods:

  • Create a thread to wait on MAXIMUM_WAIT_OBJECTS handles, then wait on that thread plus the other handles. Use this technique to break the handles into groups of MAXIMUM_WAIT_OBJECTS.
  • Call RegisterWaitForSingleObject to wait on each handle. A wait thread from the thread pool waits on MAXIMUM_WAIT_OBJECTS registered objects and assigns a worker thread after the object is signaled or the time-out interval expires.



回答2:


You don't need to write all of that code. The easiest way to implement a threadsafe singleton is to use Scott Meyer's singleton idiom:

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

An even easier way would be to use a std::atomic<int> type for the counter member variable. Then the mutex and lock guards can be omitted at all.



来源:https://stackoverflow.com/questions/46018050/issue-with-threadsafe-singleton-with-semaphore

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!