5
votes

In multithreading (2 thread) program, I have this code:

while(-1)
{
    m.lock();

    (...)

    m.unlock();
}

m is a mutex (in my case a c++11 std::mutex, but I think it'doesn't change if I use different library).

Assuming that the first thread owns the mutex and it's done something in (...) part. The second thread tried to acquire the mutex, but it's waiting that the first thread release m.

The question is: when thread 1 ends it's (...) execution and unlocks the mutex, can we be sure that thread 2 acquires the mutex or thread 1 can re-acquire again the mutex before thread 2, leaving it stucked in lock()?

5
OT: as used above that should be scope-locked, not manually locked and unlocked as you have it. A thrown exception out of the while loop will hang the mutex otherwise (unless perhaps you're counting on that).WhozCraig
I have only spended days on multi-threaded programming so I'm no expert on this but your logic/code offers at least 2 problems: 1) doesn't use the RAII paradigm 2) you should avoid user-managed mutex. For example boost::thread offers a lock on the mutex based on the scope which is a better thing compared to this snippet of code if you ask me.user1849534

5 Answers

4
votes

The C++ standard doesn't make any guarantee about the order locks to a mutex a granted. Thus, it is entirely possible that the active thread keeps unlock()ing and lock()ing the std::mutex m without another thread trying to acquire the lock ever getting to it. I don't think the C++ standard provides a way to control thread priorities. I don't know what you are trying to do but possibly there is another approach which avoids the problem you encounter.

3
votes

If both threads are equal priority, there is no such guarantee by standard mutex implementations. Some OS's have a lis of "who's waiting", and will pick the "longest waiting" when you release something, but that is an implementation detail, not something you can reliably depend on.

And imagine that you have two threads, each running something like this:

m.lock();

(...)

m.unlock();
(...)    // Clearly not the same code as above (...)
m.lock();

(...)    // Some other code that needs locking against updates. 

m.unlock();

Would you want the above code to switch thread on the second lock, every time?

By the way, if both threads run with lock for the entire loop, what is the point of a lock?

1
votes

There are no guarantees, as the threads are not ordered in any way with respect to each other. In fact, the only synchronisation point is the mutex locking.

It's entirely possible that the first thread reacquires the lock immediately if for example it is running the function in a tight loop. Typical implementations have a notification and wakeup mechanism if any thread is sleeping on a mutex, but there may also be a bias for letting the running thread continue rather than performing a context switch... it's very much up to the implementation and the details of the platform at the time.

1
votes

There are no guarantees provided by C++ or underlying OS.

However, there is some reasonable degree of fairness determined by the thread arrival time to the critical region (mutex in this case). This fairness can be expressed as statistical probability, but not a strict guarantee. Most likely this choice will be down to OS execution scheduler, which will also consider many other factors.

-1
votes

It's not a good idea to rely on such code, so you should probably change your design. However, on some operating systems, sleep(0) will yield the thread. (Sleep(0) on Windows) Again, it's best not to rely on this.