Is it necessary to lock? - c++

I met a question in leetcode. I have viewed some solutions in the discuss. But my solution is different from others because I do not use the lock in the method first. I wonder whether my code is correct. Besides, can you give me some advice about my code?
I think it is not necessary to use unique_lock in method void first(function<void()> printFirst) like void second(function<void()> printSecond), is it right?
class Foo {
public:
Foo() {
}
void first(function<void()> printFirst) {
// cout<<1<<endl;
// printFirst() outputs "first". Do not change or remove this line.
// mtx.lock();
printFirst();
flag=1;
// mtx.unlock();
cond.notify_all();
// cout<<11<<endl;
}
void second(function<void()> printSecond) {
// cout<<2<<endl;
{
unique_lock<mutex> lk(mtx);
cond.wait(lk,[this](){return flag==1;});
// printSecond() outputs "second". Do not change or remove this line.
printSecond();
flag=2;
}
// cout<<22<<endl;
cond.notify_all();
}
void third(function<void()> printThird) {
// cout<<3<<endl;
unique_lock<mutex> lk(mtx);
cond.wait(lk,[this](){return flag==2;});
// printThird() outputs "third". Do not change or remove this line.
printThird();
flag=3;
// cout<<33<<endl;
}
mutex mtx;
condition_variable cond;
int flag=0;
};

Obviously your three element functions are supposed to be called by different threads. Thus you need to lock the mutex in each thread to protect the common variable flag from concurrent access. So you should uncomment mtx.lock() and mtx.unlock() in first to protect it there as well. Functions second and third apply a unique_lock as an alternative for that.
Always make sure to unlock the mutex before calling cond.notify_all() either by calling mtx.unlock() before or making the unique_lock a local variable of an inner code block as in second.
Further advice
Put a private: before the element variables at the bottom of your class definition to protect them from outside access. That will ensure that flag cannot be altered without locking the mutex.

It is necessary.
That your code produced correct output in this instance is besides the point. It is entirely possibly that printFirst might not be complete by the timeprintSecond is called. You need the mutex to prevent this and stop printSecond and printThird. from being ran at the same time.

The flag checking condition in second() or third() may be evaluated at the same time as first() assigns 1 to flag.
Rewrite this
cond.wait(lk, [this](){return flag==1;});
like this and it may be easier to see:
while(!(flag==1)) cond.wait(lk);
It does the same thing as your wait() with a lambda.
flag is supposed to be read while the mutex is held - but first does not care about mutexes and assigns to flag whenever it pleases. For non-atomic types this is a disaster. It may work 10000000 times (and probably will) - but when things actually happen at the same time (because you let it) - boom - Undefined Behaviour

Related

How to detect if my program enters a self-deadlock?

I have multi-threaded program and it only has 1 mutex. I want to make the program terminate if it attempts to grab the lock if it already has it.
My actual program is pretty complicated. Of course we try to avoid deadlocks on a programming level. But just in case we miss a edge case, we prefer it to fail immediately rather than deadlock.
See a minimal example below.
std::mutex lock;
void f1() {
std::lock_guard<mutex> guard1(lock);
// some code ...
}
void f2() {
std::lock_guard<mutex> guard2(lock);
f1(); // Will deadlock here! How can I make it terminate instead of deadlock?
}
std::mutex provides no mechanism for accomplishing what you describe.
Instead of deadlock detection, you should be looking at deadlock avoidance. Careful programming, including appropriate choice of mutex role and scope, can help. Refactoring could help, too. For example, you could change your example code to
std::mutex lock;
static void f1_impl() {
// some code ...
}
void f1() {
std::lock_guard<mutex> guard1(lock);
f1_impl();
}
void f2() {
std::lock_guard<mutex> guard2(lock);
f1_impl();
}
But if that doesn't get you all the way to where you want to be, then you might want to consider using std::recursive_mutex instead of std::mutex. That addresses the problem by allowing a thread that already holds the mutex locked to lock it again.

When would getters and setters with mutex be thread safe?

Consider the following class:
class testThreads
{
private:
int var; // variable to be modified
std::mutex mtx; // mutex
public:
void set_var(int arg) // setter
{
std::lock_guard<std::mutex> lk(mtx);
var = arg;
}
int get_var() // getter
{
std::lock_guard<std::mutex> lk(mtx);
return var;
}
void hundred_adder()
{
for(int i = 0; i < 100; i++)
{
int got = get_var();
set_var(got + 1);
sleep(0.1);
}
}
};
When I create two threads in main(), each with a thread function of hundred_adder modifying the same variable var, the end result of the var is always different i.e. not 200 but some other number.
Conceptually speaking, why is this use of mutex with getter and setter functions not thread-safe? Do the lock-guards fail to prevent the race-condition to var? And what would be an alternative solution?
Thread a: get 0
Thread b: get 0
Thread a: set 1
Thread b: set 1
Lo and behold, var is 1 even though it should've been 2.
It should be obvious that you need to lock the whole operation:
for(int i = 0; i < 100; i++){
std::lock_guard<std::mutex> lk(mtx);
var += 1;
}
Alternatively, you could make the variable atomic (even a relaxed one could do in your case).
int got = get_var();
set_var(got + 1);
Your get_var() and set_var() themselves are thread safe. But this combined sequence of get_var() followed by set_var() is not. There is no mutex that protects this entire sequence.
You have multiple concurrent threads executing this. You have multiple threads calling get_var(). After the first one finishes it and unlocks the mutex, another thread can lock the mutex immediately and obtain the same value for got that the first thread did. There's absolutely nothing that prevents multiple threads from locking and obtaining the same got, concurrently.
Then both threads will call set_var(), updating the mutex-protected int to the same value.
That's just one possibility that can happen here. You could easily have multiple threads acquiring the mutex sequentially and thus incrementing var by several values, only to be followed by some other, stalled thread, that called get_var() several seconds ago, and only now getting around to calling set_var(), thus resetting var to a much smaller value.
The code show in thread-safe in a sense that it will never set or get partial value of the variable.
But your usage of the methods does not guarantee that value will correctly change: reading and writing from multiple threads can collide with each other. Both threads read the value (11), both increment it (to 12) and than both set to the same (12) - now you counted 2 but effectively incremented only once.
Option to fix:
provide "safe increment" operation
provide equivalent of InterlockedCompareExchange to make sure value you are updating correspond to original one and retry as necessary
wrap calling code into separate mutex or use other synchronization mechanism to prevent operations to intermix.
Why don't you just use std::atomic for the shared data (var in this case)? That will be more safe efficient.
This is an absolute classic.
One thread obtains the value of var, releases the mutex and another obtains the same value before the first thread has chance to update it.
Consequently the process risks losing increments.
There are three obvious solutions:
void testThreads::inc_var(){
std::lock_guard<std::mutex> lk(mtx);
++var;
}
That's safe because the mutex is held until the variable is updated.
Next up:
bool testThreads::compare_and_inc_var(int val){
std::lock_guard<std::mutex> lk(mtx);
if(var!=val) return false;
++var;
return true;
}
Then write code like:
int val;
do{
val=get_var();
}while(!compare_and_inc_var(val));
This works because the loop repeats until it confirms it's updating the value it read. This could result in live-lock though in this case it has to be transient because a thread can only fail to make progress because another does.
Finally replace int var with std::atomic<int> var and either use ++var or var.compare_exchange(val,val+1) or var.fetch_add(1); to update it.
NB: Notice compare_exchange(var,var+1) is invalid...
++ is guaranteed to be atomic on std::atomic<> types but despite 'looking' like a single operation in general no such guarantee exists for int.
std::atomic<> also provides appropriate memory barriers (and ways to hint what kind of barrier is needed) to ensure proper inter-thread communication.
std::atomic<> should be a wait-free, lock-free implementation where available. Check your documentation and the flag is_lock_free().

pthread_mutex_lock how to not lock when it is the same thread

I'm using pthread_mutex_t for locking.
pthread_mutex_t m_lock;
void get1() {
cout<<"Start get 1"<<endl;
pthread_mutex_lock(&m_lock);
get2();
pthread_mutex_unlock(&m_lock);
cout<<"End get 1"<<endl;
}
void get2() {
cout<<"Start get 2"<<endl;
pthread_mutex_lock(&m_lock); // The program actually stops here because it waits to m_lock to be unlock from get1 function.
pthread_mutex_unlock(&m_lock);
cout<<"End get 2"<<endl;
}
// The thread call to run function
void* run(void* p) {
get1();
}
Lets say I have only one thread that calls to run function, so:
get1 lock the m_lock and call to get2, but when it tries to lock m_lock, it waits that the lock will be unlock (something that not happen) and we got a deadlock.
My question is how can I avoid this case when the same thread that locked the lock in get1, will not need to wait for the lock in get2 (because it is the same thread)?
For example, in Java this case never can happen when you use synchornized.
public Test implements Runnable {
public void get1() {
System.out.println("Start get 1");
synchronized (this) {
get2();
}
System.out.println("End get 1");
}
public void get2() {
System.out.println("Start get 2");
synchronized (this) {
}
System.out.println("End get 2");
}
#Override
public void run() {
get1();
}
}
No deadlock here.
I want the same result in my C code please.
Thanks.
As noted by Kami Kaze in the comments, if this is your full example, then it's a non-issue: there's only one path leading to get2, and this path already acquires the mutex; simply omit acquiring it a second time.
However, in general, it's possible to think of scenarios where it's not that clear. In this case, you can make the mutex recursive/reentrant:
In computer science, the reentrant mutex (recursive mutex, recursive lock) is particular type of mutual exclusion (mutex) device that may be locked multiple times by the same process/thread, without causing a deadlock.
In your settings, this would be via pthread_mutexattr_settype:
pthread_mutexattr_settype(&m_lock, PTHREAD_MUTEX_RECURSIVE);
This is called lock recursion.
The last argument to pthread_mutex_init is an attributes struct. You can set the attributes to allow recursive locking with pthread_mutexattr_settype(..., PTHREAD_MUTEX_RECURSIVE).
But, I must add some editorial content here. I believe very strongly that lock recursion is almost always a bug. Or it will lead to impossible to debug bugs later in the programs life time.
A locking operation can be reasoned to mean "when the lock function returns the object protected by the lock is in a known state and this state will not change until the unlock function is called". This means that if get1 has started to modify the object you protect with the lock and then get2 recurses that lock, this contract is broken twice. First because get2 succeeds obtaining the lock while the object is not in a known state, second because the object is modified while get1 thinks it owns the lock.
Sure, we often get away with doing things like this but it is a terrible practice. Redesign your program to not recurse locks. The standard way to do this would be to implement a function called get2_locked and get2 obtains the lock and calls get2_locked while get1 already knows it has the lock and would call get2_locked.
With this:
pthread_mutex_lock(&m_lock);
get2();
pthread_mutex_unlock(&m_lock);
you have locked the entire get2(). So, there's no point in taking the same lock again inside get2() function.
Just remove the locking and unlocking code from get2().
If only the code part in get2() requires a locking then get rid of the locking and unlocking from get1() function.
For example, in Java this case never can happen when you use
synchornized.
In your code there the synchronized regions are not interlinked. So, for a similar comparison, you need to use a different mutex in get2() function.
I assume that get1 really does more than just acquire the lock and call get2? Otherwise what is the point of get1?
If that's the case you could solve it by having a get3 function which does the main part of get2 (the part you don't show here) and which doesn't lock. Then call that new function from get1 instead (and of course from get too):
void get1()
{
// Do something here
cout<<"Start get 1"<<endl;
pthread_mutex_lock(&m_lock);
get3(); // <-- Note call get3 instead here
pthread_mutex_unlock(&m_lock);
cout<<"End get 1"<<endl;
// Do something more here
}
void get2()
{
cout<<"Start get 2"<<endl;
pthread_mutex_lock(&m_lock); // The program actually stops here because it waits to m_lock to be unlock from get1 function.
get3(); // <-- Note call to get3 here
pthread_mutex_unlock(&m_lock);
cout<<"End get 2"<<endl;
}
void get3()
{
// Do the actual work of get2 here...
// Note: No locking here
}

how to insert vector only once in multiple thread

I have below code snippet.
std::vector<int> g_vec;
void func()
{
//I add double check to avoid thread need lock every time.
if(g_vec.empty())
{
//lock
if(g_vec.empty())
{
//insert items into g_vec
}
//unlock
}
...
}
func will be called by multiple thread, and I want g_vec will be inserted items only once which is a bit similar as singleton instance. And about singleton instance, I found there is a DCLP issue.
Question:
1. My above code snippet is thread safe, is it has DCLP issue?
2. If not thread safe, how to modify it?
Your code has a data race.
The first check outside the lock is not synchronized with the insertion inside the lock. That means, you may end up with one thread reading the vector (through .empty()) while another thread is writing the vector (through .insert()), which is by definition a data race and leads to undefined behavior.
A solution for exactly this kind of problem is given by the standard in form of call_once.
#include<mutex>
std::vector<int> g_vec;
std::once_flag g_flag;
void func()
{
std::call_once(g_flag, [&g_vec](){ g_vec.insert( ... ); });
}
In your example, it could happen that second reentrant thread will find a non empty half initialized vector, that it's something that you won`t want anyway. You should use a flag, and mark it when initialization job is completed. Better a standard one, but a simple static int will do the job as well
std::vector<int> g_vec;
void func()
{
//I add double check to avoid thread need lock every time.
static int called = 0;
if(!called)
{
lock()
if(!called)
{
//insert items into g_vec
called = 1;
}
unlock()
}
...
}

Query std::mutex for lock state

I have a situation where I'd like to do something like that shown below, but there doesn't seem to be a way of querying the mutex without changing its state. I don't want the someFunctionCalledRepeatedlyFromAnotherThread() to hang around waiting for the mutex to free up if it is locked. It must return immediately after performing some alternative action. I'm guessing this omission is there for safety, as the lock may free up in the time between querying it and the function returning. In my case, bad stuff will not happen if the lock is freed while doSomeAlternativeAction() is happening. The fact I'm in this situation probably means I'm doing something wrong, so how should I change my design?
class MyClass
{
std::mutex initMutex;
public:
void someInitializationFunction()
{
std::lock_guard<std::mutex> lock(initMutex);
// Do some work
}
void someFunctionCalledRepeatedlyFromAnotherThread()
{
if (initMutex.isLocked())
{
doSomeAlternativeAction();
return;
}
// otherwise . . .
std::lock_guard<std::mutex> lock(initMutex);
// carry on with work as usual
}
}
Asking mutex for its state is useless: it may be unlocked now, but by the time you get around to lock it, it may be locked. So it does not have such method.
It does, however, have a method try_lock() which locks it if it is not locked and returns true if it acquired the lock and false otherwise. And std::unique_lock (the more advanced version of std::lock_guard) has option to call it.
So you can do:
void someFunctionCalledRepeatedlyFromAnotherThread()
{
std::unique_lock<std::mutex> lock(initMutex, std::try_to_lock);
if(!lock.owns_lock())
{
doSomeAlternativeAction();
return;
}
// otherwise ... go ahead, you have the lock
}
Sounds like you want to use std::unique_lock instead of std::lock_guard. The try_lock method works similar to the TryEnterCriticalSection on Windows, whereby the function will atomically acquire the lock and return 'true' if it can, or just return 'false' if the lock cannot be acquired (and will not block). Refer to http://msdn.microsoft.com/en-us/library/hh921439.aspx and http://en.cppreference.com/w/cpp/thread/unique_lock/try_lock. Note that unique_lock also has other members available for trying to lock such as try_lock_for and try_lock_until.