2

On follow link (http://www.cplusplus.com/reference/mutex/mutex/try_lock/) we have declared that sample can return only values from 1 to 100000. Does it is declared that 0 can't be in output?

// mutex::try_lock example
#include <iostream>       // std::cout
#include <thread>         // std::thread
#include <mutex>          // std::mutex

volatile int counter (0); // non-atomic counter
std::mutex mtx;           // locks access to counter

void attempt_10k_increases () {
  for (int i=0; i<10000; ++i) {
    if (mtx.try_lock()) {   // only increase if currently not locked:
      ++counter;
      mtx.unlock();
    }
  }
}

int main ()
{
  std::thread threads[10];
  // spawn 10 threads:
  for (int i=0; i<10; ++i)
    threads[i] = std::thread(attempt_10k_increases);

  for (auto& th : threads) th.join();
  std::cout << counter << " successful increases of the counter.\n";

  return 0;
}

In any case, it's easy to answer 'How to get 2?', but really not clear about how to get 1 and never get 0.

The try_lock can "fail spuriously when no other thread has a lock on the mutex, but repeated calls in these circumstances shall succeed at some point", but if it true, then sample can return 0 (and also can return 1 in some case).

But, if this specification sample declared true and 0 cannot be in output, then words about "fail spuriously" maybe not true then?

aefimov
  • 51
  • 5
  • would you call 10000 calls 'repeated calls'? – marc Jan 17 '15 at 22:44
  • 1
    Ah, [the joys of cplusplus.com](http://stackoverflow.com/q/6520052/596781). Though if you're pedantic, the site doesn't claim that 0 is impossible. It just claims that 1-100000 are possible. – Kerrek SB Jan 17 '15 at 22:45
  • I'd say it's one of edge cases of global progress guarantees that are very hard to formalize from within the language, but where it's sort of assumed that on any reasonable platform, a failure of `try_lock` implies that *some* other thread *at some point* made progress. – Kerrek SB Jan 17 '15 at 22:48
  • @kerrek-sb why site does not declare [0..100000] instead? Does this mean that "fail spuriously" can happen but not in single first initial try_lock? – aefimov Jan 18 '15 at 07:49
  • @aefimov: I don't know why the site says what it says, I didn't write it. As I said, I don't think there exists any real hardware on which 0 is an actual outcome, but I also don't think that the standard guarantees that. – Kerrek SB Jan 18 '15 at 11:10

3 Answers3

2

The Standard says the following:

30.4.1.2/14 [thread.mutex.requirements.mutex]

An implementation may fail to obtain the lock even if it is not held by any other thread. [ Note: This spurious failure is normally uncommon, but allows interesting implementations based on a simple compare and exchange (Clause 29). —end note ]

So you can even get 0 if all of try_lock fail.

Also, please do not use cplusplus.com, it has a long history of having lots of mistakes.
It's safer to use cppreference.com which is much closer to the Standard

Community
  • 1
  • 1
Abyx
  • 12,345
  • 5
  • 44
  • 76
1

try_lock can fail if another thread held a lock and just released it, for example. You read that "repeated calls in these circumstances shall succeed at some point". Doing 10,000 calls to try_lock will count as "repeated calls" and one of them will succeed.

gnasher729
  • 51,477
  • 5
  • 75
  • 98
  • This means that you can get 0 also, but it declared as impossible if we respect to words on cplusplus.com (only values [1..100000] is declared) :) – aefimov Jan 18 '15 at 00:10
-1

You can never get 0:

When first call to try_lock() happens (doesn't matter which thread is here first) the mutex is unlocked. This means that 1 of the 10 threads will manage to lock the mutex, meaning try_lock() will succeed.

You can get 1:

  • Lets say thread 0 manages to lock the mutex:

void attempt_10k_increases () { for (int i=0; i<10000; ++i) { if (mtx.try_lock()) { // thread 1 to 9 are here ++counter; // thread 0 is here mtx.unlock(); } } }

  • Now we say that the OS scheduler chose to not run thread 0 for a little while. In the meantime, thread 1 to 9 keep running, calling try_lock() and failing, because thread 0 holds the mutex.

    • Thread 1 to 9 are now done. They failed to acquire the mutex even once.
    • Thread 0 gets reschuled. It unlock the mutex and finish.
    • Counter is now 1.
Xaqq
  • 4,308
  • 2
  • 25
  • 38
  • To get this you need all threads for 10000 times failed try_lock, and one thread fail 9999 times and last call success. – aefimov Jan 18 '15 at 00:06
  • @aefimov Well the first call is very likely to succeed. "This function may fail spuriously when no other thread has a lock on the mutex, but repeated calls in these circumstances shall succeed at some point." i guess my example is a bit stupid, but i considered the "at some point" being after thread0 `unlock()` for the first time in my example. This isn't very likely though. And I don't think it's possible for all threads to be failing at the same time for 10k calls. – Xaqq Jan 18 '15 at 00:27