Thread: Race condition: getting multiple threads to cooperate

  1. #1
    Registered User
    Join Date
    Mar 2005
    Location
    New Zealand
    Posts
    20

    Race condition: getting multiple threads to cooperate

    I'm currently writing a server program that listens for incoming incoming network transport and spawns a new thread for each new connection.

    Now all these threads will be accessing a certain function at several different times, and while one thread is calling the function I want to block the other threads from executing the same code at the same time to prevent possible (nowever unlikely or uncritical) race conditions. Is there some simple method of doing this? I want the solution to be robust as I expect the program to be running for months on end without stopping.

    The program is intended for the win2k/xp platform and want it to complie no trouble in both VC6+ and BC5+.

  2. #2
    Registered User
    Join Date
    Dec 2004
    Posts
    95
    Executing the same code is fine, it's modifying shared data that you need to protect. Th fact you thought otherwise leads me to believe you need to learn a bit more about threading and synchronization before you dive into this.

    That said, you will likely want some locking, e.g. mutex (or in Windows-speak CRITICAL_SECTION).

    wa gotta run.

  3. #3
    Registered User
    Join Date
    Mar 2005
    Location
    New Zealand
    Posts
    20
    The problem is not so much locking shared data, but more to the point the serial port. I don't wont one thread coming along and interrupting another whilest its communicating on it. I would have though the easiest way to prevent problems is to block one thread from running that particular code/function that accesses the port while another thread is running it.

    Maybe I'm just missing something? I can see a way of doing by using a bogus object that a thread locks then it enters the function, and can be used to block other threads execution of the function until it is unlocked at the end of the function- but it doesn't seem like a very elegant solution.

  4. #4
    Registered User Mortissus's Avatar
    Join Date
    Dec 2004
    Location
    Brazil, Porto Alegre
    Posts
    152
    You could use semaphores. Donīt know how they work in Windows.

  5. #5
    Registered User
    Join Date
    Mar 2005
    Location
    New Zealand
    Posts
    20
    Ahh it seems that I can use InitialiseCriticalSection(), EnterCriticalSection(), LeaveCriticalSection() and DeleteCriticalSection(). This seems to be aimed at threads of the same process as opposed to mutex which is between threads on different processes.

    To be able for all the threads to access the threadBlocker it seems I must make it global, or either create a new object in which to encapsulate everything that get passed to the new threads. Or is it possible to pass more than one object to a new thread?

    I think this is about what I need to do (a brief overview of my program):
    Code:
    CRITICAL_SECTION threadBlocker;
    
    int main()
    {
       InitializeCriticalSection((LPCRITICAL_SECTION) threadBlocker);
    
       InitialiseEveryThing();
       CreateThread(start master server thread);
    
       while(some global condition) {
          sleep(...);
          if(some condition)
             actAsClientAndDoStuff();
       }
    
       DeleteCriticalSection((LPCRITICAL_SECTION) threadBlocker);
       killEveryThingElse();
       return 0;
    }
    
    DWORD masterServerThread(...)
    {
       As required {
          CreateThread(server listener thread);
       }
    }
    
    DWORD listenerServerThread(...)
    {
       validateUserEtc();
       while(some cond) {
          getRemoteCommand();
          serialCommand();
       }
    
       closeConnection();
    }
    
    void serialCommand(...)
    {
       EnterCriticalSection(threadBlocker);
       serialCommunicae{}
       LeaveCriticalSection(threadBlocker);
    }
    Last edited by FlyingDutchMan; 03-30-2005 at 09:38 AM.

  6. #6
    Registered User
    Join Date
    Dec 2004
    Posts
    95
    Ahh it seems that I can use InitialiseCriticalSection(), EnterCriticalSection(), LeaveCriticalSection() and DeleteCriticalSection(). This seems to be aimed at threads of the same process as opposed to mutex which is between threads on different processes.
    Yep. (N.b. I use the term mutex to refer to CRIT_SECT because it's in line with pthreads terminology).

    To be able for all the threads to access the threadBlocker it seems I must make it global, or either create a new object in which to encapsulate everything that get passed to the new threads. Or is it possible to pass more than one object to a new thread?
    You could pass a pointer to a struct containing all the data required for the thread, e.g.
    Code:
    struct thread_stuff {
    char *something;
    int something_else;
    CRITICAL_SECTION* thread_lock;
    };
    That said, I'd wrap CRIT_SECT up in a C++ object.
    Scoped RAII locking also helps, especially when you have multiple return paths from a function where you locked your mutex.

    Also:

    Your "while some cond" loops should probably be turned into condition variable waits.

    Presumably you're setting your "some cond" from one thread and then testing from another to see if there's work available, or whatever - you should probably use a condition variable & mutex to wait on the condition, rather than using sleep.

    Side note: boost provides an OO mutex, condition variable, and scoped RAII lock.

  7. #7
    Registered User
    Join Date
    Mar 2005
    Location
    New Zealand
    Posts
    20
    Thanks for that. Good to know I wasn't going to far off track.

    The sleep is so it can update itself every 5 mins or so (connect to other computers with the same setup). According the borland C help I have here it suspends the threads execution until the time is up. The intended method of exiting the program is through a network connection so the global is there just waiting for that. I'll probably stick that global in the object that gets passed to the threads so that its no longer global (I hate globals!). You are right though - there will be an unseemly wait of upto 5 mins before exiting the main loop. I will have to get that one tieded up.

    The masterServerThread uses the listen() so that doesn't use anything until a connection comes in.

    The listenServerThread loop is waiting on data from the network so
    that should also be a non resource hogging wait, and the threads survival would be lucky to exceed 1 or 2 seconds (hence the unlikelyhood of race condidtions).

    Scoped RAII locking also helps, especially when you have multiple return paths from a function where you locked your mutex.
    And some pureists say that there should only be one entry and exit point in functions... which would solve that problem, but I can't be assed being a pureist. I'll just settle for stable - I don't think it'll be much of an issue to put a LeaveCriticalSection() before every return.

  8. #8
    It's full of stars adrianxw's Avatar
    Join Date
    Aug 2001
    Posts
    4,829
    A critical section and a mutex are different objects on a Windows system. A critical section can only used by the threads of a single process. It is very fast and has a low overhead. A named mutex can be used across process boundaries to synchronise threads in several different programs.

    I have a very basic MT tutorial starting here but you've got the general idea now anyway.
    Wave upon wave of demented avengers march cheerfully out of obscurity unto the dream.

  9. #9
    Registered User
    Join Date
    Dec 2004
    Posts
    95
    And some pureists say that there should only be one entry and exit point in functions... which would solve that problem, but I can't be assed being a pureist. I'll just settle for stable - I don't think it'll be much of an issue to put a LeaveCriticalSection() before every return.
    Some do say that (personally I think it's stupid to restrict yourself like that, it all depends on the situation), but in the presence of exceptions, there can't be one exit point. RAII/scoped locking is very useful there.

    Even if you don't use exceptions, in general it's a good idea to use things like scoped locks if you have them available, because it makes your code easier to maintain - if you add an extra return path and forget to call LeaveCrit, then you're in trouble.

    My point about condition variables was more about keeping
    a) access to the shared variable thread-safe, and
    b) ensuring proper visibility of updates to it.

    E.g. if you do something like

    Code:
    int working = 0; //assume int assignment is atomic on your platform
    
    int main ( ) {
    
    beginthread ( ... );
    
    while (working) { sleep ( ); }
    
    printresults ( .... );
    }
    
    void* threadfunc (void*) {
    
    // .. do stuff ..
    working = 1;
    }
    Your main thread may not necessarily see the latest value of working, because the assignment in the worker thread lacked the proper instructions to ensure visibility propagation.

    Using a mutex (CS), or one of the Interlocked*** family of instructions should ensure proper visibilty. You should use them anyway in this situation, because "int" may not always be atomically modifiable on your platform.

    Anyway I'm rambling. Generally you'll be fine as long as you protect shared resources appropriately (that inclues variables, devices, etc)..

  10. #10
    Registered User
    Join Date
    Mar 2005
    Location
    New Zealand
    Posts
    20
    Quote Originally Posted by adrianxw
    A critical section and a mutex are different objects on a Windows system. A critical section can only used by the threads of a single process. It is very fast and has a low overhead. A named mutex can be used across process boundaries to synchronise threads in several different programs.

    I have a very basic MT tutorial starting here but you've got the general idea now anyway.
    Thanks for that... I got the tutorial working perfectly. I'm using the WaitForSingleObject() in the main program loop and after the time out iit can do the client stuff, or if the server thread dies, it will exit straight away. Much better.

  11. #11
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    More reading assignments:
    Multithreading for Rookies
    About Synchronization

    gg

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Need help with multiple threads
    By Cogman in forum Windows Programming
    Replies: 2
    Last Post: 07-05-2009, 09:40 AM
  2. Multiple Threads, One listener.
    By PING in forum Networking/Device Communication
    Replies: 3
    Last Post: 03-27-2009, 12:19 PM
  3. Multiple Threads
    By NuNn in forum C Programming
    Replies: 3
    Last Post: 03-14-2009, 11:29 PM
  4. Race condition
    By Roaring_Tiger in forum C Programming
    Replies: 5
    Last Post: 10-24-2004, 09:42 PM
  5. Modeless Dialogs in Multiple threads
    By MrGrieves in forum Windows Programming
    Replies: 0
    Last Post: 06-22-2004, 01:33 PM