/* * 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 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 lock1(mutex_1); std::lock_guard lock2(mutex_2); } void thread2_bad() { std::lock_guard lock2(mutex_2); std::lock_guard 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 lock1(mutex_1, std::defer_lock); std::unique_lock lock2(mutex_2); } void thread2_ok() { std::lock_guard lock2(mutex_2); std::lock_guard 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(mutex_1, mutex_2); mutex_1.unlock(); mutex_2.unlock(); } void bar_ok() { std::lock(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 lock(mutex_); } void interproc1_bad() { std::lock_guard lock(mutex_); interproc2_bad(); } void foo_ok() { { std::lock_guard lock(mutex_); } int i = 0; { std::lock_guard lock(mutex_); } } void bar_ok() { std::unique_lock lock1(mutex_, std::defer_lock); std::lock_guard lock2(mutex_); } void complicated_bad() { std::unique_lock lock1(mutex_, std::defer_lock); std::lock_guard lock2(mutex_); lock1.lock(); } private: std::mutex mutex_; }; class PathSensitive { public: void FP_ok() { std::lock_guard l(mutex_); bool flag = false; if (flag) { std::lock_guard l(mutex_); } } private: std::mutex mutex_; }; } // namespace basics