2

I have a program with several worker threads, and a main thread that receives jobs. In the main thread I want to queue the jobs onto a synchronized queue, and have the worker threads sitting there all waiting on the queue. When there's something in the queue I want the worker to pull the job from the queue, while the remaining work sits there waiting for another job.

I found CreateMsgQueue (http://msdn.microsoft.com/en-us/library/ms885180.aspx) however this appears to only exist for Windows CE.

I know I could write this myself, however if something already existed I'd be a fool not to use it.

I am developing in c++ using Visual Studio 2005.

Any suggestions gratefully received.

Thanks Rich

Rich
  • 3,722
  • 5
  • 33
  • 47

1 Answers1

4

Windows doesn't provide exactly what you want. What it does provide is thread pools -- with these, you not only don't have to create the queue yourself, but you don't have to create or (directly) manage the threads either.

Of course, synchronized queues do exist too, just not as part of Windows. One I wrote looks like this:

#ifndef QUEUE_H_INCLUDED
#define QUEUE_H_INCLUDED

#include <windows.h>

template<class T, unsigned max = 256>
class queue { 
    HANDLE space_avail; // at least one slot empty
    HANDLE data_avail;  // at least one slot full
    CRITICAL_SECTION mutex; // protect buffer, in_pos, out_pos

    T buffer[max];
    long in_pos, out_pos;
public:
    queue() : in_pos(0), out_pos(0) { 
        space_avail = CreateSemaphore(NULL, max, max, NULL);
        data_avail = CreateSemaphore(NULL, 0, max, NULL);
        InitializeCriticalSection(&mutex);
    }

    void push(T data) { 
        WaitForSingleObject(space_avail, INFINITE);       
        EnterCriticalSection(&mutex);
        buffer[in_pos] = data;
        in_pos = (in_pos + 1) % max;
        LeaveCriticalSection(&mutex);
        ReleaseSemaphore(data_avail, 1, NULL);
    }

    T pop() { 
        WaitForSingleObject(data_avail,INFINITE);
        EnterCriticalSection(&mutex);
        T retval = buffer[out_pos];
        out_pos = (out_pos + 1) % max;
        LeaveCriticalSection(&mutex);
        ReleaseSemaphore(space_avail, 1, NULL);
        return retval;
    }

    ~queue() { 
        DeleteCriticalSection(&mutex);
        CloseHandle(data_avail);
        CloseHandle(space_avail);
    }
};

#endif
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • Thanks Jerry, really nice solution. I think I like your queue more than thread pooling. – Rich Jun 16 '10 at 15:46
  • 4
    You can also achieve pretty much the same with completion ports. I wrote an example showing how to do it several years ago: http://blogs.msdn.com/b/larryosterman/archive/2004/03/29/101329.aspx – Larry Osterman Jun 17 '10 at 05:46
  • 2
    Im with Larry on this one. Don't re-invent the wheel: Completion ports implement a queues job dispatching mechanism already. – Chris Becke Jun 17 '10 at 07:57
  • I'm with Chris and Larry. Use completion ports. – Len Holgate Jun 17 '10 at 10:04
  • @Chris, Len: There's nothing wrong with re-inventing the wheel, especially when the one you're replacing is rectangular. – Jerry Coffin Jun 17 '10 at 17:44
  • @Jerry: If you use an auto-reset event, you have different scalability problem - if there are a large number of elements inserted in the queue at the same time, you only wake up one thread which means you spend excess time in the kernel waking up threads (this is largely fixed in Win7 with the removal of the dispatcher spin lock). – Larry Osterman Jun 18 '10 at 00:21
  • Jerry, IMHO IOCP are generally better for this kind of thing due to how they limit the number of threads that run and keep the same threads running and so prevent unnecessary context switches where possible. You simply can't achieve the same in user mode code and so they'll always have an inherent advantage that will make them a better choice than hand rolled code; simply wrap them in to make them conform to your required interface. – Len Holgate Jun 24 '10 at 14:21
  • The @LarryOsterman completion ports blog post was moved. https://learn.microsoft.com/en-us/archive/blogs/larryosterman/so-you-need-a-worker-thread-pool – Mirko Ploch Dec 08 '22 at 22:10