Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8351955
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 9, 20262026-06-09T08:48:29+00:00 2026-06-09T08:48:29+00:00

Because the lack of condition variable in windows(though it is introduced since vista, it’s

  • 0

Because the lack of condition variable in windows(though it is introduced since vista, it’s not supported in windows XP and 2003), it is not very easy to implement a thread-safe queue in c++. Strategies for Implementing POSIX Condition Variables on Win32. What I required is to just use CriticalSection or Mutex and Event without using semaphore and condition variable.

I also tried to find an exact implementation that just using win32 native API, but no luck. So I finished one by myself. The problem is I am not 100% sure the code is thread-safe. Who can tell me it is OK or not?

class CEventSyncQueue
{
public:
    CEventSyncQueue(int nCapacity = -1);
    virtual ~CEventSyncQueue();
    virtual void Put(void* ptr);
    virtual void* Get();
protected:
    int m_nCapacity;
    CPtrList m_list;

    CRITICAL_SECTION m_lock;    
    HANDLE m_hGetEvent;
    HANDLE m_hPutEvent;
};

CEventSyncQueue::CEventSyncQueue(int nCapacity)
{
    m_nCapacity = nCapacity;

    ::InitializeCriticalSection(&m_lock);
    m_hPutEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
    m_hGetEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
}

CEventSyncQueue::~CEventSyncQueue()
{
    m_list.RemoveAll();

    ::CloseHandle(m_hGetEvent);
    ::CloseHandle(m_hPutEvent);

    ::DeleteCriticalSection(&m_lock);
}

void CEventSyncQueue::Put(void* ptr)
{
    ::EnterCriticalSection(&m_lock);

    while(m_nCapacity > 0 && m_list.GetCount() >= m_nCapacity)
    {
        ::LeaveCriticalSection(&m_lock);

        //wait
        if(::WaitForSingleObject(m_hPutEvent, INFINITE) != WAIT_OBJECT_0)
        {
            ASSERT(FALSE);
        }

        ::EnterCriticalSection(&m_lock);
    }
    if(m_nCapacity > 0)
    {
        ASSERT(m_list.GetCount() < m_nCapacity);
    }
    m_list.AddTail(ptr);

    ::SetEvent(m_hGetEvent);    //notifyAll
    ::LeaveCriticalSection(&m_lock);
}
void* CEventSyncQueue::Get()
{
    ::EnterCriticalSection(&m_lock);

    while(m_list.IsEmpty())
    {
        ::LeaveCriticalSection(&m_lock);

        //wait
        if(::WaitForSingleObject(m_hGetEvent, INFINITE) != WAIT_OBJECT_0)
        {
            ASSERT(FALSE);
        }

        ::EnterCriticalSection(&m_lock);
    }
    ASSERT(!m_list.IsEmpty());
    void* ptr = m_list.RemoveHead();

    ::SetEvent(m_hPutEvent);    //notifyAll
    ::LeaveCriticalSection(&m_lock);

    return ptr;
}
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-09T08:48:30+00:00Added an answer on June 9, 2026 at 8:48 am

    On second thoughts, it’s hardly necessary to explicitly implement a semaphore. Instead, just think about how you would implement a semaphore using events, and approach your the problem that way. My first attempt used manual-reset events, which was inefficient but manifestly correct, and then I optimized.

    Please note that I haven’t debugged (or even compiled!) either of these code fragments, but they should give you the right idea. Here’s the manual-reset version:

    class CEventSyncQueue
    {
    public:
        CEventSyncQueue(int nCapacity = -1);
        virtual ~CEventSyncQueue();
        virtual void Put(void* ptr);
        virtual void* Get();
    protected:
        int m_nCapacity;
        CPtrList m_list;
    
        CRITICAL_SECTION m_lock;    
        HANDLE m_queue_not_empty;
        HANDLE m_queue_not_full;
    };
    
    CEventSyncQueue::CEventSyncQueue(int nCapacity)
    {
        m_nCapacity = nCapacity;
        ::InitializeCriticalSection(&m_lock);
        m_queue_not_empty = ::CreateEvent(NULL, TRUE, FALSE, NULL);
        m_queue_not_full = ::CreateEvent(NULL, TRUE, TRUE, NULL);
    }
    
    CEventSyncQueue::~CEventSyncQueue()
    {
        m_list.RemoveAll();
        ::CloseHandle(m_queue_not_empty);
        ::CloseHandle(m_queue_not_full);
        ::DeleteCriticalSection(&m_lock);
    }
    
    void CEventSyncQueue::Put(void* ptr)
    {
        bool done = false;
        while (!done)
        {
            // If the queue is full, we must wait until it isn't.
            if(::WaitForSingleObject(m_queue_not_full, INFINITE) != WAIT_OBJECT_0)
            {
                ASSERT(FALSE);
            }
    
            // However, we might not be the first to respond to the event,
            // so we still need to check whether the queue is full and loop
            // if it is.
            ::EnterCriticalSection(&m_lock);
            if (m_nCapacity <= 0 || m_list.GetCount() < m_nCapacity)
            {
                m_list.AddTail(ptr);
                done = true;
                // The queue is definitely not empty.
                SetEvent(m_queue_not_empty);
                // Check whether the queue is now full.
                if (m_nCapacity > 0 && m_list.GetCount() >= m_nCapacity)
                {
                    ResetEvent(m_queue_not_full);
                }
            }
            ::LeaveCriticalSection(&m_lock);
        }
    }
    
    void* CEventSyncQueue::Get()
    {
        void *result = nullptr;
        while (result == nullptr)
        {
            // If the queue is empty, we must wait until it isn't.
            if(::WaitForSingleObject(m_queue_not_empty, INFINITE) != WAIT_OBJECT_0)
            {
                ASSERT(FALSE);
            }
    
            // However, we might not be the first to respond to the event,
            // so we still need to check whether the queue is empty and loop
            // if it is.
            ::EnterCriticalSection(&m_lock);
            if (!m_list.IsEmpty())
            {
                result = m_list.RemoveHead();
                ASSERT(result != nullptr);
                // The queue shouldn't be full at this point!
                ASSERT(m_nCapacity <= 0 || m_list.GetCount() < m_nCapacity);
                SetEvent(m_queue_not_full);
                // Check whether the queue is now empty.
                if (m_list.IsEmpty())
                {
                    ResetEvent(m_queue_not_empty);
                }
            }
            ::LeaveCriticalSection(&m_lock);
        }
    }
    

    And here’s the more efficient, auto-reset events version:

    class CEventSyncQueue
    {
    public:
        CEventSyncQueue(int nCapacity = -1);
        virtual ~CEventSyncQueue();
        virtual void Put(void* ptr);
        virtual void* Get();
    protected:
        int m_nCapacity;
        CPtrList m_list;
    
        CRITICAL_SECTION m_lock;    
        HANDLE m_queue_not_empty;
        HANDLE m_queue_not_full;
    };
    
    CEventSyncQueue::CEventSyncQueue(int nCapacity)
    {
        m_nCapacity = nCapacity;
        ::InitializeCriticalSection(&m_lock);
        m_queue_not_empty = ::CreateEvent(NULL, FALSE, FALSE, NULL);
        m_queue_not_full = ::CreateEvent(NULL, FALSE, TRUE, NULL);
    }
    
    CEventSyncQueue::~CEventSyncQueue()
    {
        m_list.RemoveAll();
        ::CloseHandle(m_queue_not_empty);
        ::CloseHandle(m_queue_not_full);
        ::DeleteCriticalSection(&m_lock);
    }
    
    void CEventSyncQueue::Put(void* ptr)
    {
        if (m_nCapacity <= 0)
        {
            ::EnterCriticalSection(&m_lock);
            m_list.AddTail(ptr);
            SetEvent(m_queue_not_empty);
            ::LeaveCriticalSection(&m_lock);
            return;
        }
    
        bool done = false;
        while (!done)
        {
            // If the queue is full, we must wait until it isn't.
            if(::WaitForSingleObject(m_queue_not_full, INFINITE) != WAIT_OBJECT_0)
            {
                ASSERT(FALSE);
            }
    
            // However, under some (rare) conditions we'll get here and find
            // the queue is already full again, so be prepared to loop.
            ::EnterCriticalSection(&m_lock);
            if (m_list.GetCount() < m_nCapacity)
            {
                m_list.AddTail(ptr);
                done = true;
                SetEvent(m_queue_not_empty);
                if (m_list.GetCount() < m_nCapacity)
                {
                    SetEvent(m_queue_not_full);
                }
            }
            ::LeaveCriticalSection(&m_lock);
        }
    }
    
    void* CEventSyncQueue::Get()
    {
        void *result = nullptr;
        while (result == nullptr)
        {
            // If the queue is empty, we must wait until it isn't.
            if(::WaitForSingleObject(m_queue_not_empty, INFINITE) != WAIT_OBJECT_0)
            {
                ASSERT(FALSE);
            }
    
            // However, under some (rare) conditions we'll get here and find
            // the queue is already empty again, so be prepared to loop.
            ::EnterCriticalSection(&m_lock);
            if (!m_list.IsEmpty())
            {
                result = m_list.RemoveHead();
                ASSERT(result != nullptr);
                // The queue shouldn't be full at this point!
                if (m_nCapacity <= 0) ASSERT(m_list.GetCount() < m_nCapacity);
                SetEvent(m_queue_not_full);
                if (!m_list.IsEmpty())
                {
                    SetEvent(m_queue_not_empty);
                }
            }
            ::LeaveCriticalSection(&m_lock);
        }
    }
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I avoided CodePlex because of it's lack of support for proper SVN and was
Because shells other than ksh do not support pass-by-reference, how can multiple arrays be
because when I use the function getUser () do not get the correct id?
I'm creating a database with this structure (4 Tables): https://i.stack.imgur.com/vPaoD.png (Can't embed because lack
i used to use jquery validation plugin but because of lack of this plugin
I have a friend who has an assignment on arrays and because I lack
I had Postgres 9.0.x installed with homebrew, but because of lack of some modules
This is probably because a lack experience with both Java and Android development, but
i know about query notifications, but they're so limited because of lack of support
Because of lack of screen space, i try to display description (UILabel appearing right

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.