You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

154 lines
2.8 KiB

/*
* Copyright (c) 2018-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <mutex>
namespace basics {
class Basic {
public:
Basic() {}
// deadlock between thread1_bad() and thread2_bad()
void thread1_bad() {
mutex_1.lock();
mutex_2.lock();
mutex_2.unlock();
mutex_1.unlock();
}
void thread2_bad() {
mutex_2.lock();
mutex_1.lock();
mutex_1.unlock();
mutex_2.unlock();
}
private:
std::mutex mutex_1;
std::mutex mutex_2;
};
class WithGuard {
public:
WithGuard() {}
// deadlock between thread1_bad() and thread2_bad()
void thread1_bad() {
std::lock_guard<std::mutex> lock1(mutex_1);
std::lock_guard<std::mutex> lock2(mutex_2);
}
void thread2_bad() {
std::lock_guard<std::mutex> lock2(mutex_2);
std::lock_guard<std::mutex> lock1(mutex_1);
}
private:
std::mutex mutex_1;
std::mutex mutex_2;
};
class DeferredGuard {
public:
DeferredGuard() {}
// NO deadlock between thread1_bad() and thread2_bad()
void thread1_ok() {
std::unique_lock<std::mutex> lock1(mutex_1, std::defer_lock);
std::unique_lock<std::mutex> lock2(mutex_2);
}
void thread2_ok() {
std::lock_guard<std::mutex> lock2(mutex_2);
std::lock_guard<std::mutex> lock1(mutex_1);
}
private:
std::mutex mutex_1;
std::mutex mutex_2;
};
class StdLock {
public:
StdLock() {}
// no reports, std::lock magically avoids deadlocks
void foo_ok() {
std::lock<std::mutex>(mutex_1, mutex_2);
mutex_1.unlock();
mutex_2.unlock();
}
void bar_ok() {
std::lock<std::mutex>(mutex_2, mutex_1);
mutex_2.unlock();
mutex_1.unlock();
}
private:
std::mutex mutex_1;
std::mutex mutex_2;
};
class SelfDeadlock {
public:
SelfDeadlock() {}
void thread_bad() {
mutex_.lock();
mutex_.lock();
mutex_.unlock();
mutex_.unlock();
}
void interproc2_bad() { std::lock_guard<std::mutex> lock(mutex_); }
void interproc1_bad() {
std::lock_guard<std::mutex> lock(mutex_);
interproc2_bad();
}
void foo_ok() {
{ std::lock_guard<std::mutex> lock(mutex_); }
int i = 0;
{ std::lock_guard<std::mutex> lock(mutex_); }
}
void bar_ok() {
std::unique_lock<std::mutex> lock1(mutex_, std::defer_lock);
std::lock_guard<std::mutex> lock2(mutex_);
}
void complicated_bad() {
std::unique_lock<std::mutex> lock1(mutex_, std::defer_lock);
std::lock_guard<std::mutex> lock2(mutex_);
lock1.lock();
}
private:
std::mutex mutex_;
};
class PathSensitive {
public:
void FP_ok() {
std::lock_guard<std::mutex> l(mutex_);
bool flag = false;
if (flag) {
std::lock_guard<std::mutex> l(mutex_);
}
}
private:
std::mutex mutex_;
};
} // namespace basics