Skip to main content
GameDev.net gamedev.net
🔒 Locked

2 threads alternating processing

Started by floatingwoods Jan 5, 2012 at 5:05 PM 12 replies 2.3k views
Original Post
floatingwoods
floatingwoods
Hello,

What is the best way of implementing 2 threads that alternatively operate (but never at the same time), by reducing the waiting time to a maximum?

I though about using a CCriticalSection object, but can't get it working consistently (and fast!). Ideally, when one thread is done with its task, the other thread should do its task. When that second thread is done, then the first thread should do some other task, etc.
It is important that both threads do not waste time, except for waiting for the other thread.

Thanks for any insight
Tribad
Tribad
Events would be my choice. You can wait on them and the threads signaling the event to each other
Telastyn
Telastyn

What is the best way of implementing 2 threads that alternatively operate (but never at the same time), by reducing the waiting time to a maximum?


Have thread A run, and thread B wait.

If you've got two threads only working on something, but never at the same time, you're never running them concurrently... and shouldn't use threads.
floatingwoods
floatingwoods
Thanks to both replies.


[quote name='floatingwoods' timestamp='1325783116' post='4900006']
What is the best way of implementing 2 threads that alternatively operate (but never at the same time), by reducing the waiting time to a maximum?


Have thread A run, and thread B wait.

If you've got two threads only working on something, but never at the same time, you're never running them concurrently... and shouldn't use threads.
[/quote]

I need two non-concurrently running threads for the transition. I have to rewrite a single-threaded application. In future the 2 threads will run concurrently, but until I finished preparing the individual API locks, this intermediate solution is best.
"Have thread A run and thread B wait" Yes! But how?
e.g.
[source]
CCriticalSection cs;

THREAD1:
while (true)
{
cs.Lock()
do some work
cs.Unlock()
}

THREAD2:
while (true)
{
cs.Lock()
do some work
cs.Unlock()
}

[/source]

Above solution works. But I don't have the guarantee that thread 1 will not run twice before thread 2 runs. I need an alternating pattern.
iMalc
iMalc
Agreed, using threads is the wrong thing if you specifically want no concurrency.

Also, this does not make sense: "reducing the waiting time to a maximum". You can reduce something to a minimum or you can increase it to the maximum, those are your choices.

Edit: Okay then, use events.
Telastyn
Telastyn

I need an alternating pattern.


No you don't. You won't be guaranteed it in the concurrent version, so you shouldn't worry about it for the intermediate version.

Frankly I don't see any benefit of the intermediate version. You're not accomidating any concurrency for testing. You're not doing any new and interesting work.... I don't get it.


"Have thread A run and thread B wait" Yes! But how?
[/quote]


// Thread 1
while(true){
work();
}

// Thread 2
while(true){
// die in a fire.
}
Kobo
Kobo

Thanks to both replies.

[quote name='Telastyn' timestamp='1325783627' post='4900012']
[quote name='floatingwoods' timestamp='1325783116' post='4900006']
What is the best way of implementing 2 threads that alternatively operate (but never at the same time), by reducing the waiting time to a maximum?


Have thread A run, and thread B wait.

If you've got two threads only working on something, but never at the same time, you're never running them concurrently... and shouldn't use threads.
[/quote]

I need two non-concurrently running threads for the transition. I have to rewrite a single-threaded application. In future the 2 threads will run concurrently, but until I finished preparing the individual API locks, this intermediate solution is best.
"Have thread A run and thread B wait" Yes! But how?
e.g.
[source]
CCriticalSection cs;

THREAD1:
while (true)
{
cs.Lock()
do some work
cs.Unlock()
}

THREAD2:
while (true)
{
cs.Lock()
do some work
cs.Unlock()
}

[/source]

Above solution works. But I don't have the guarantee that thread 1 will not run twice before thread 2 runs. I need an alternating pattern.
[/quote]

You need two locks. Make each one unlock the other. I'm not sure that's really a lock anymore, though. Make one lock start locked and make each thread depend on its own lock. You will have starvation issues, which is one reason this is a bad idea.
Narf the Mouse
Narf the Mouse
Sounds like you want Thread B to wait until Thread A signals, then vice-versa. What does your language of choice have for signaling between threads?
floatingwoods
floatingwoods
Again thanks for the replies!

Telastyn: The application that used to run on a single thread now has to run on 2 threads (including external plugins). This requires many changes as you can imagine for a large application. Before there was no need at all to lock resources. With 2 threads there is a need to lock every single resource. Now, I can start to implement every single resource lock and test if the 2 threads work fine in one month. Or... I can have the intermediate solution where I start having my 2 threads run their respective code without having to worry about resource locking and have a running application now. And slowly implement resource locking and test gradually.
In addition to that, I need a "compatibility mode" where old plugins will still run with the new framework (old plugins (that I don't even have the source code for) still think there is only one thread running!). In the compatibility mode I will forbid the concurrent execution, and guarantee the alternating pattern

Well, the previous framework was ill-conceived, so yes, I have not an ideal solution.

I am compiling with MSVC and MFC, but can also compile with Mingw and Qt. So I was thinking about using CCriticalSection and QMutex
Tribad
Tribad
Mutex and CriticalSection are for to prevent concurrent execution of the same code.
Having two threads that update a queue is a good example. One writes to the queue and another reads from it. Its only a question of time that the queue data is currupted.
You need events. Each thread has an event to wait on. With Win32 you can create events and use WaitForSingleObject to wait on that event to get signaled.
floatingwoods
floatingwoods

Mutex and CriticalSection are for to prevent concurrent execution of the same code.
Having two threads that update a queue is a good example. One writes to the queue and another reads from it. Its only a question of time that the queue data is currupted.
You need events. Each thread has an event to wait on. With Win32 you can create events and use WaitForSingleObject to wait on that event to get signaled.


Thanks. It seems that I will have to go with events (WaitForSingleObject and QWaitCondition)
Antheus
Antheus
If you're using C++, look into boost::asio, along with strand object. It was designed specifically for backporting legacy code that isn't thread-safe. There's also support for thread-local storage for any resources that might need to be shared or preserved, depending on various conditions.

Aside from good portability, the post/dispatch API with callbacks also allows explicit ordering, allowing you complete control over sequential execution. It also takes care of some other gotchas, such as timeouts, which become necessary in applications that were not designed for multi-processing.
Telastyn
Telastyn

Telastyn: The application that used to run on a single thread now has to run on 2 threads (including external plugins). This requires many changes as you can imagine for a large application. Before there was no need at all to lock resources. With 2 threads there is a need to lock every single resource. Now, I can start to implement every single resource lock and test if the 2 threads work fine in one month. Or... I can have the intermediate solution where I start having my 2 threads run their respective code without having to worry about resource locking and have a running application now. And slowly implement resource locking and test gradually.
In addition to that, I need a "compatibility mode" where old plugins will still run with the new framework (old plugins (that I don't even have the source code for) still think there is only one thread running!). In the compatibility mode I will forbid the concurrent execution, and guarantee the alternating pattern


Personally it seems like a lot of effort to thread/coordinate the operations instead of simply implement them as alternating within one thread (in your compatibility mode/until you're ready to test resource locking).

My concern would be that plugins would violate concurrency in code you can't see regardless of coordination you might do.
alvaro
alvaro
It sounds like you are trying to use coroutines.

Although C and C++ are not natural languages for coroutines, they can be implemented by using setjmp/longjmp or non-standard functions; for instance, POSIX provides getcontext/setcontext/makecontext/swapcontext precisely to allow this type of code (I just noticed the Wikipedia page on coroutines mentions these functions).

There is a library called Boost.Coroutine, but it doesn't seem to be ready for prime time, and I couldn't get it to work last time I tried.

Topic Locked

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

Sign in to reply to this topic.