Skip to main content
gamedev.net
🔒 Locked

Thread Inter-Syncronization

Started by Prozak 16 replies 1.3k views
Original Post
Prozak
Prozak
Ok, here is my problem: - A is a Socket Data Receiving Thread - B is processing Data, and Sending it out to a Client - A must signal B that data has arrived - B is allways alive, so geting some sort of signal from A is relatively simple using some sort of Mutex or something - Problem comes when 1) A must know that B has processed its data and 2) A cannot continue until B as processed its data. But I do not want to have A busy waiting for B, I would like to find a way to block the A thread, have a blocking wait, instead of a busy wait, where A sits in a loop asking "has B processed the data, can I continue?". Any ideas?
_winterdyne_
_winterdyne_
Use a semaphore, or implement something like:

bool waitBool(bool evaluate){    while (!evaluate)    {        Thread::yield();    }};


Where Thread::yield is a function that sleeps the current thread.
Winterdyne Solutions Ltd is recruiting - this thread for details!
kuphryn
kuphryn
queue

Kuphryn
Prozak
Prozak
Ok, but I don't want to have the thread suspended, because then, who would wake it up?

And I really didn't want to go into a sleep/check cycle, because that is too granular...

Blocking is pretty much what I'm looking for here...
vetroXL
vetroXL
Hi,

Are you on a windows system? If you are, then I would recommend asynchronous I/O or I/O Completion ports... MSDN has good articles on them...

If you're not, have a look at the boost thread library.. they have some good synch objects... They have one that is really good that I used to help with the reader/writer problem that you are describing...

Prozak
Prozak
Quote:
Original post by vetroXL
Hi,

Are you on a windows system? If you are, then I would recommend asynchronous I/O or I/O Completion ports... MSDN has good articles on them...

If you're not, have a look at the boost thread library.. they have some good synch objects... They have one that is really good that I used to help with the reader/writer problem that you are describing...


Thanks for the reply.

Yes, this is a Windows 2000/XP Project, and also for PDAs (WinCE). I really don't have the time nor the energy to go into boost for this, and any solution I find must work on both platforms...

@kuphryn: Could you please elaborate? Where would GDNet be without single-word replies...
vetroXL
vetroXL
Ahh, well then Boost is out of the question if you're on a PDA system... I would recomend looking up Asynchrousouse I/O or I/O Completion ports.. you'll have to decide which one works best for you situation... but they both have built in notification schemes to help with synch issues...

I use I/O completion ports if I have to build a large scalable server... but Asycnh I/o is fine if you have less then 64 simultaneous clients (sp) or if you writting a client.
Prozak
Prozak
Quote:
Original post by vetroXL
Ahh, well then Boost is out of the question if you're on a PDA system... I would recomend looking up Asynchrousouse I/O or I/O Completion ports.. you'll have to decide which one works best for you situation... but they both have built in notification schemes to help with synch issues...

I use I/O completion ports if I have to build a large scalable server... but Asycnh I/o is fine if you have less then 64 simultaneous clients (sp) or if you want a client.


Nope, not a solution either, I've already built a whole system around this design, so I'm not going to go in another direction at the first sight of trouble, eheh...

I just need a way to block A, and have B unblock A.
rick_appleton
rick_appleton
Well, as you know I've just completed the threaded part of my resource loader, and it uses Boost::Condition for exactly what you want.

If you're not willing to use Boost for this, you can always see how they've implemented it. The Boost::Thread library seems pretty small, so it shouldn't be that hard.

Other than that, the term you need to search for is 'conditional variable'.
vetroXL
vetroXL
wow! tough customer ;)

Have tried an event based system like this?

Lock( DWORD dwTimeWait = INFINITE )
{
WaitForSingleObject( m_hLock, dwTimeWait );
ResetEvent( m_hLock );
}

UnLock()
{
SetEvent( m_hLock );
}
dormlock
dormlock
Why not use a conditional. A would wait on the condtional and B could then signal the conditional causing A to wake up.
Prozak
Prozak
Quote:
Original post by vetroXL
wow! tough customer ;)

Have tried an event based system like this?

Lock( DWORD dwTimeWait = INFINITE )
{
WaitForSingleObject( m_hLock, dwTimeWait );
ResetEvent( m_hLock );
}

UnLock()
{
SetEvent( m_hLock );
}


Thanks VetroXL, I've worked with Threads and mutexes before, but I don't yet have experience with Events. Are Events used to signal other Threads? What API calls should I be looking at?

Rate++ [wink]
vetroXL
vetroXL
Hi,

They are used for those purposes exactly, light weight signal objects...
CreateEvent is what is used above, they are Manual reset events, not Auto reset events... (btw I use that in production code on a distributed-parallel-warfare-simulaiton-system )

You can also use OpenEvent to open exsiting events...

THe semantics are the same as the mutuxes...

Tthanks for the Rate++
Bregma
Bregma
You shouldn;t have A waiting on B at all. You should have A waiting on its socket and posting the data it reads to a work queue. B needs to be waiting on the work queue.

A would be structured like this.
  loop forever    wait for data to appear on socket    read socket into buffer    grab queue mutex      enqueue data      signal queue-not-empty condition    ungrab queue mutex  end loop

B would be structured like this.
  grab queue mutex  loop forever    wait on queue-not-empty condition    unqueue data    process data  end loop

Granted, you need to have an additional mutex guarding your queue so you can enqueue/unqueue multiple data packets without deadlock, but that's the idea. Each thread has one and only one loop invariant on which it will block while the invariant does not hold, and those invariants are different. Anything else is just inviting either deadlock or starvation.
Stephen M. Webb
Professional Free Software Developer
yadango
yadango
actually sounds more like a producer-consumer problem. i'd use a mutex to control access to shared data and multiple events to signal B has finished processing and B can process data. A can only continue when it has the mutex and B has finished processing (which is what I think you want).

A
-
1.) A (the producer) waits for the mutex.
2.) if the buffer is full or has enough data to be processed, then you release the mutex and wait until B has signaled the finished processing event.
3.) Repeat 1 and 2 until you have both the mutex and "B has finished processing" event.
4.) Produce more data.
5.) If there's enough data from B to consume, pulse a "B can process" event.

B
-
1.) B (the consumer) waits for the mutex.
2.) If there is nothing or not enough to consume, release the mutex and wait for the "B can process" event.
3.) Otherwise, if there is data to consume, process it, release the mutex, and pulse the "B has finished processing" event.
Bregma
Bregma
I recommend you read this. It has loads of relevant examples. Whatever you do, avoid busy-waits and lock-step solutions.
Stephen M. Webb
Professional Free Software Developer

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.