3

Having read Can mutex implementations be interchanged (independently of the thread implementation), it is my understanding that I can ensure that my class is thread safe for all thread implementations, by using C++ 11 mutexes.

Am I correct in my understanding? I am expecting either yes (perhaps with caveats) or no (with reasons).

  • My code may need recompilation on the target platform, but no changes are needed to my source code. (@Peter)
  • Alternatively stated, I ought to be able to compile for a particular platform and deliver a .so that can be safely used with any thread library?

Given the down voting, I will try to be more precise.

Is the C++11 implementation of mutexes independent of any other thread API? Do C++11 mutexes only know about each other and implement blocking independently of how the thread of execution reached that point.

Will a C++11 mutex always work with OpenMP (with recompilation) ? Can Team A deliver a thread safe API (using C++ mutexes) for use by Team B, regardless of the particular thread API used by Team B? All code can be recompiled.

I am attaching a working example.

#include <iostream>
#include <omp.h>
#include <mutex>
class A {
    unsigned n = 0;

public:

    void inc() {
        ++n;
    }

    unsigned get() {
        return n;
    }
};

class B {
    std::mutex mutex;
    unsigned n = 0;

public:

    void inc() {
        mutex.lock();
        ++n;
        mutex.unlock();

    }

    unsigned get() {
        return n;
    }
};

int main() {

    A a;
    B b;
#pragma omp parallel for
    for (int i = 0; i < 100000; i++) {
        a.inc();
        b.inc();
    }

    std::cout << a.get() << " " << b.get() << std::endl;

}

The output of my last run was:

98015 100000

Is this by luck or design?

fundagain
  • 398
  • 1
  • 6
  • 23
  • What do you want as an answer? – Passer By Sep 02 '17 at 08:14
  • Yes or no. I think the answer is yes, but I may be mistaken. If no then a reason? – fundagain Sep 02 '17 at 08:18
  • @Passer By Do you know the answer? – fundagain Sep 02 '17 at 08:20
  • The question I referenced asks a different question and I am inferring an answer to my question from answers given in that post. But I am by no means certain. I have to put my head on a block so am just checking. – fundagain Sep 02 '17 at 08:26
  • It depends on what you mean by "interchange" of implementations. If you mean that your code can be ported from one implementation (compiler and its standard library) to another then the answer is yes. If you mean code is compiled with one compiler and linked against the standard library associated with another compiler, then the answer is "no". – Peter Sep 02 '17 at 08:37
  • @Peter. Thank you. I mean with recompilation. With suitable recompilation, a client can use my class with openmp, or c++ 11 threads, or any other thread library. My class will still be atomic. No source code changes needed. – fundagain Sep 02 '17 at 08:43
  • Please give reasons for down voting. I obviously have problem I can't answer. Most I can. If the answer is obvious, or I have not done enough research, then down vote but hit me with a comment at least. I can take it. If the question is badly phrased, tell me. But down voting but not giving criticism is not helpful. – fundagain Sep 02 '17 at 09:18

2 Answers2

2

you can make your class platform-independently thread-safe if you make all its members private and all access (read/write) operations on data protected by any synchronization mechanism (std::mutex, std::atomic, or other from boost/Qt/whatever), regardless of thread API in use.

Simplest way is to use a single std::recursive_mutex/std::unique_lock pair for all data access operations (getters/setters) inside class and make data members private. It is just guaranteed to work regardless of thread API, but may be not optimal performance-wise.

Most other solutions may be or be not suitable for your specific case. Sometimes synchronization primitives are not required at all.

Andrei R.
  • 2,374
  • 1
  • 13
  • 27
  • 1
    Thanks Andrei R. That is my understanding. I will wait a while for anyone to contradict you, and then post this as the answer (with your head on the block :). – fundagain Sep 02 '17 at 11:39
  • 1
    This is true assuming the protected code is guaranteed not to reenter under any circumstances (in case of recursive_mutex - not to reenter unless it is designed to). E.g. as a counter example: some kind of fiber/tasks API like boost::fiber, a functions get a mutex and then calls some fiber-aware async API; the API switches current thread to run another fiber which in turn calls the same function which tries to get same mutex again. That would result in a deadlock (for fast mutex) or unforeseen "concurrent" data access (for recursive mutex). – Andrey Turkin Sep 02 '17 at 11:50
  • in general, "possibly deadlockable" doesn't mean "not thread-safe", it's a different kind of error – Andrei R. Sep 02 '17 at 12:14
  • 1
    @Andrey Turkin I appreciate, and will note, your comment, but Andrei R is correct, I feel, within the spirit of my question. – fundagain Sep 02 '17 at 12:33
1

You can always use mutexes to make the member functions of a class interact without data races. But that's not enough to ensure that an object can be used from multiple threads without conflicts; you need a broader design. For example, consider writing out the contents of a vector:

int size = vec.size();
for (int i = 0; i < size; ++i)
    std::cout << vec[i] << ' ';
std::cout << '\n';

With an internal mutex, the call to vec.size() and the calls to vec::operator[] do not have data races, so they are "safe" to call from multiple threads. But this code has a problem: if another thread removes an element from the vector then the vector will be smaller than it was, and this loop will run off the end.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
  • Assuming I have completely controlled my object with C++11 mutexes, and have completely controlled issues you are highlighting (which seem to be standard threading issues which I take control of via the mutexes), will the mutexes work against both std::threads *and* openmp threads, and any other thread implementation? – fundagain Sep 02 '17 at 10:59