Thread: Question on boss/workers threaded programming model

  1. #1
    Registered User
    Join Date
    Aug 2004
    Posts
    77

    Question on boss/workers threaded programming model

    Here's the scenario as best I can explain it briefly:

    I have one boss thread that recieves and distributes jobs to a set number of continuously running Worker threads. I don't think I have the option to start new threads when a new job is created, nor can I have the threads close when they are done processing their current job.

    I had intended to communicate between them using a queue for the thread. The Boss thread would get jobs for the workers and place them in various worker thread's queues. These jobs the Workers have to perform have varying lengths of time needed for processing so there's no guarentees on when one will be completed and the next started.

    The problem I have is how to block the Workers when their queue is empty. I don't want them constantly polling the queue looking for work, that would needlessly bog down the CPU. And I can't have them lock a mutex or semaphore when the queue is empty since that lock will be assigned to the Worker not the Boss so the Boss thread won't be able to add to the queue.

    Is there a way to block the thread (without using the Sleep() function) until something is placed in the queue? Or is the method I'm trying to implement just never going to work?

    Thanks in advance for any help or suggestions.

  2. #2
    It's full of stars adrianxw's Avatar
    Join Date
    Aug 2001
    Posts
    4,829
    A way to do this would be to create an event object for each worker thread. The thread can then use WaitForSingleObject() to enter a non-busy wait, and the boss thread can signal the event for the thread which it has work for.

    If the worker threads have message loops, you can just use PostThreadMessage() to wake it up.
    Wave upon wave of demented avengers march cheerfully out of obscurity unto the dream.

  3. #3
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    If I have thought this through correctly, a semaphore would be the ideal solution. The semaphore solution should allow multiple threads to consume events from the same queue. A semaphore will not block the boss thread.
    Code:
    // Worker thread...
    WaitForSingleObject(hSem, INFINITE); /* Blocks if semaphore count is zero.
                                            Decrements semaphore count when thread is released. */
    EnterCriticalSection(&cs);
    
    my_work_item = myqueue.front();
    myqueue.pop();
    
    LeaveCriticalSection(&cs);
    Code:
    // Boss thread...
    hSem = CreateSemaphore(NULL, 0, LONG_MAX, NULL); /* Create semaphore with initial count of zero. */
    
    ...
    
    // Add work item...
    EnterCriticalSection(&cs);
    
    myqueue.push(a_work_item);
    
    LeaveCriticalSection(&cs);
    
    ReleaseSemaphore(hSem, 1, NULL); /* Increments semaphore count. */
    >> A way to do this would be to create an event object for each worker thread. The thread can then use WaitForSingleObject() to enter a non-busy wait, and the boss thread can signal the event for the thread which it has work for. <<

    Codeplug has previously posted a nice queue solution that uses an event. However, with this solution, you can only have one worker thread consuming events from each queue. This seems to be the model you are using, so shouldn't be a problem.

    Using windows queues are another solution. However, these suffer serious security issues. Another process on the same desktop can post messages to your queue, even if it is running under a less priviliged user.

    Multi-threading issues are notoriously easy to stuff up and notoriously hard to debug so good luck.
    Last edited by anonytmouse; 12-12-2004 at 02:23 PM.

  4. #4
    It's full of stars adrianxw's Avatar
    Join Date
    Aug 2001
    Posts
    4,829
    >>>
    However, with this solution, you can only have one worker thread consuming events from each queue.
    <<<

    It seemed to me that this is exactly what the OP was looking for? A non busy wait within a thread until there was something for that specific thread to do.

    I don't know the details of his program, it sounds to me like there is a serious design fault, but this will get around that.

    How are you interpreting his set up?

    >>>
    Another process on the same desktop can post messages to your queue, even if it is running under a less priviliged user.
    <<<

    Yes, but then they could also send messages to the top level program.... Being able to post messages to the thread to say there is work available does not mean that the rogue program would be able to place items into the other programs queue.
    Wave upon wave of demented avengers march cheerfully out of obscurity unto the dream.

  5. #5
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    Quote Originally Posted by adrianxw
    >>>
    However, with this solution, you can only have one worker thread consuming events from each queue.
    <<<

    It seemed to me that this is exactly what the OP was looking for? A non busy wait within a thread until there was something for that specific thread to do.

    I don't know the details of his program, it sounds to me like there is a serious design fault, but this will get around that.

    How are you interpreting his set up?
    Yep, that was my interpretation also. I was just stating a limitation. Besides, I think, by changing a couple of lines of code, the event solution could probably be made to work with multiple consumer threads. Either way, a workable solution could be created with an event, mutex or semaphore.

    Quote Originally Posted by AdrianXW
    >>>
    Another process on the same desktop can post messages to your queue, even if it is running under a less priviliged user.
    <<<

    Yes, but then they could also send messages to the top level program.... Being able to post messages to the thread to say there is work available does not mean that the rogue program would be able to place items into the other programs queue.
    My point was that using a message loop as the actual queue is probably not ideal, which is not particularly related to your suggestion for waking up a thread with a message loop. Call it a case of non-optimal quoting.

    I thought of a couple of other platform dependent solutions. The first is I/O completion ports and the second is thread pooling.

  6. #6
    It's full of stars adrianxw's Avatar
    Join Date
    Aug 2001
    Posts
    4,829
    >>> a workable solution could be created with an event, mutex or semaphore.

    Agree totally.

    >>> probably not ideal

    Again, agree, but it is an easy solution.

    In this kind of situation, my design approach has always been to have a thread that accepts a "work packet" class pointer, processes it, then tidies up and exits. When the next workpacket is available, I spin a new worker thread to process it. It makes everything tidy, but he specifically says that is not an option - sounds like a dodgy design to me, but without further details, who can say.
    Wave upon wave of demented avengers march cheerfully out of obscurity unto the dream.

  7. #7
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    Depending on the amount of time it takes to process a "work packet", it may be benificial to eliminate the constant overhead of thread creation and destruction. Using a Semaphore instead of a manual reset Event in the MTqueue<> implementation would be the easiest way to get a multiple comusers and producers capable queue up and running. The only catch is that when a thread aquires the semaphore it must call de_que() in order to keep the semphore count and the queue size in sync.

    But yall knew that.

    gg

  8. #8
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    I think that if you change the event to auto-reset and change the following lines:
    Code:
            if (sz == 1)
                ResetEvent(m_ev); // m_q is empty now
    to:
    Code:
            if (sz > 1)
                SetEvent(m_ev); // Set the event to signalled to wake up another thread (or not block when we are called again)
    that MTqueue<> can be used with multiple consumer threads. I think.

  9. #9
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    Yeah I thought of that at first too. The only problem is that you really need that resource counter that a semaphore provides. For example - with no thread waiting, a producer could add two items to the queue - SetEvent() is called twice - then two threads wait on the handle but only one is woken up. There is now a blocked thread and job waiting to be processed.

    gg

  10. #10
    Registered User
    Join Date
    Aug 2004
    Posts
    77
    Thanks for all of the suggestions.

    I was kinda hoping this scenario happened more often, but the sentiment about it being a poor design has me concerned. What I was attempting to do was a method of dealing with window event handling. I wanted to have one thread recieve all of the events then passs them out to individual threads that process the event for individual windows.

    I was hoping to get a standard method of having each window in its own thread so if at any point one got bogged down in an intensive loop it wouldn't lock the other windows. Thats the reason I didn't want to use the normal boss/worker model, I figured it was easier to keep the messages processed in order if one thread did them.

    I suppose its back to the drawing board on this one.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. another do while question
    By kbpsu in forum C++ Programming
    Replies: 3
    Last Post: 03-23-2009, 12:14 PM
  2. multiple file loading. so fruturated! help!
    By psychopath in forum Game Programming
    Replies: 5
    Last Post: 05-09-2005, 05:13 PM
  3. Help with file reading/dynamic memory allocation
    By Quasar in forum C++ Programming
    Replies: 4
    Last Post: 05-17-2004, 03:36 PM
  4. a question that will make you think
    By DavidP in forum Game Programming
    Replies: 5
    Last Post: 11-18-2003, 05:19 PM
  5. Question...
    By TechWins in forum A Brief History of Cprogramming.com
    Replies: 16
    Last Post: 07-28-2003, 09:47 PM