C Board  

Go Back   C Board > General Programming Boards > C++ Programming

Reply
 
LinkBack Thread Tools Display Modes
Old 03-30-2005, 06:40 AM   #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+.
FlyingDutchMan is offline   Reply With Quote
Old 03-30-2005, 07:31 AM   #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.
azteched is offline   Reply With Quote
Old 03-30-2005, 08:40 AM   #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.
FlyingDutchMan is offline   Reply With Quote
Old 03-30-2005, 08:59 AM   #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.
Mortissus is offline   Reply With Quote
Old 03-30-2005, 09:35 AM   #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.
FlyingDutchMan is offline   Reply With Quote
Old 03-30-2005, 10:11 AM   #6
Registered User
 
Join Date: Dec 2004
Posts: 95
Quote:
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).

Quote:
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.
azteched is offline   Reply With Quote
Old 03-30-2005, 10:35 AM   #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).

Quote:
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.
FlyingDutchMan is offline   Reply With Quote
Old 03-30-2005, 10:39 AM   #8
It's full of stars
 
adrianxw's Avatar
 
Join Date: Aug 2001
Posts: 4,833
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.
adrianxw is offline   Reply With Quote
Old 03-30-2005, 11:14 AM   #9
Registered User
 
Join Date: Dec 2004
Posts: 95
Quote:
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)..
azteched is offline   Reply With Quote
Old 03-30-2005, 09:31 PM   #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.
FlyingDutchMan is offline   Reply With Quote
Old 03-31-2005, 05:53 AM   #11
Registered User
 
Codeplug's Avatar
 
Join Date: Mar 2003
Posts: 3,844
More reading assignments:
Multithreading for Rookies
About Synchronization

gg
Codeplug is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Forum Jump

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


All times are GMT -6. The time now is 03:07 AM.


Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.3.0 RC2

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22