Jump to content
  • Advertisement
Sign in to follow this  
DrTwox

Simple communcation between threads

This topic is 3403 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi all. I'm developing a simple music playing app (using C) that uses two threads. The main thread handles the GUI, the second thread decodes various audio formats (mp3, flac, etc) and sends the PCM data to the audio hardware. Currently to control the decoder thread, the GUI thread changes the value of a variable, and the decoder checks the value of this variable every quarter second or so. The decoder can also change this variable, e.g. While loading/initializing a file, the decoder sets the status to 'e_status_buffering'. The variable, decoderStatus, is protected by a mutex lock. The code to communicate between the two threads looks something like this:
/* Pseudocode-ish; not the real code! */
enum {
    e_status_buffering,
    e_status_stop,
    e_status_play,
    e_status_pause,
    e_status_nextTrack,
    e_status_prevTrack
} e_status;

e_status decoderStatus;
mutex_t lock; /* the lock init code isn't shown here */

void decoder_SetStatus(e_status status) {
    MutexLock(lock);
    decoderStatus = status;
    MutexUnlock(lock);
}

e_status decoder_GetStatus() {
    MutexLock(lock);
    e_status status = decoderStatus;
    MutexUnlock(lock);
    return status
}

Is this an acceptable method? What would be a better way to do this?

Share this post


Link to post
Share on other sites
Advertisement
One problem I see with that is that there's no way to do an atomic "get and set" with the primitives you expose. If, when a thread is about to set the variable, it ever matters what the current state of the variable is, you're going to have a race condition. Of course, if it will always be OK to possibly have one thread have an outdated view of the variable, then that's not a problem.

In general, I find it better to express inter thread communication in terms of message-passing as opposed to state-setting whenever possible.

Share this post


Link to post
Share on other sites
I don't see anything wrong with that.

Because all access to the shared variables is done from inside a mutex lock, you don't ever need to worry about atomic reads/writes, but in this case, I think it would even work without the mutex, as both a read and a write of 4 bytes of data (or less) are already atomic, but then you may need to add volatile to your variable definition, or use memory barriers, as otherwise a write to a different address that happens later on, may appear to have happened before this one from a different thread (but if you are going to do lockless threading, make really sure you know what you're doing, as it can yield really nasty bugs. If you don't feel comfortable with that, just keep it the way it currently is, and all should be fine:)).

Share this post


Link to post
Share on other sites
Quote:
Original post by swiftcoder
Quote:
Original post by quasar3d
but then you may need to add volatile to your variable definition... make really sure you know what you're doing
QFE. Volatile does not really do what you might think it does here - required reading.


Yes, I read that before, and for writing portable multi threading code, it's indeed pretty useless, but on systems with a simple memory model (like x86), volatile does make reads and writes more consistent (in a way that another thread cannot see the result of a write to one address happen, before it can see the result of an earlier write as well). It does certainly not make operations like + and - interlocked though.

Then again, I personally never use it, and just place memory barriers, which on x86 would only block the compiler from rearranging reads/writes over that barrier, but will also function as a real memory barrier on systems that need it, like XBox360

Then again, I believe the latest visual C++ compiler actually does insert memory barriers around volatile reads/writes, so then it would work on those platforms as well, but it certainly makes it a lot slower than needed, so memory barriers are still better:)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!