Question

I have a multithreaded program with the main thread being third-party (can't change it) and pure C. My task is to build new modules (in C++) around it, those reside partly in other threads and need to use the C program's interface. Basically just reading some variables (ints, floats, nothing complicated) that are stored and updated in the C thread.

Now to my question: How can I make sure that I don't get rubbish out of the C interface when accessing those variables as I can't use a mutex to lock it while reading. Is this even possible? Or is writing a float/int an atomic operation anyway?

Was it helpful?

Solution 4

You cannot. Reading and writing anything is not an atomic operation and if you cannot change the C code, you are out of luck. Syncronization always needs both parts to be syncronized.

Your best bet is to ask the third party to make their part thread safe and/or share a locking mechanism with you.

OTHER TIPS

Statements like "writing a float/int [is] an atomic operation anyway" are, unfortunately, not well defined in C or C++ (although with the use of std::atomic in C++11 and the stdatomic.h methods from C11 can help here - but that's not going to help you with C interop for a library you can't modify, so you can probably ignore it here).

You can find guidance about these issues on specific compilers and platforms - for example, you can probably figure out that on most platforms, aligned 32-bit or 64-bit reads or writes will be atomic, if aligned, and that most compilers will align them appropriately.

However, down this road lies madness. If you have multiple threads involve, just use POSIX/pthreads functionality, like pthreads mutexes - which are easily accessible from both C and C++, to guard any access to state shared across threads.

Since you can't modify the C code, you may have to do all the locking in the C++ code, before any call to the C library, unlocking after. If you can read, but not modify the C code, or the document is very clear about the threading/sharing model, you may be able to use a fine grained locking strategy, but in the absence of any profiling indicating a bottleneck, I'd start with one global lock you use to guard every access to the C API.

You can't. The only right way to work in this scenario is to work only with arguments which are provided to your functions by the calling C thread - and not store any references to them afterwards. There's no way to guarantee any variables will not be modified - in general case.

You need to rethink your architecture so that such need does not arise.

If you are unable to make sure that the code which sets the variables values is synchronized, puting a lock while reading is pointless and won't work. It's not only the atomicity of the operations, it's also data visibility - updates to those variables may not be visible to other threads.

If you control the main thread you have to create a new variable for each of those you have to access, access it from the main thread, and using locks, set the value of the newly created variable. Then, from other threads, access only those synchronized variables.

int myVal = 0;

int main() {
  while(!shouldQuit()) {
    doSomeIndependentStuff();
    pthread_lock(&mutex);
    myVal = independentGlobalVal;
    pthread_unlock(&mutex);
  }
}

int getMyVal() {
  int retVal = 0;
  pthread_lock(&mutex);
  retVal  = myVal;
  pthread_unlock(&mutex);
  return retval;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top