#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <mutex>
#include <thread>
#include <cstdarg>
// 參考:http://www.cnblogs.com/haippy/p/3284540.html
namespace thread_lock {
std::mutex g_io_mutex;
//------------------------------------------------------------------------
// 1.使用std::mutex互斥鎖來解決線程安全問題。
static void Func1() {
g_io_mutex.lock();
std::cout << "Enter thread: " << std::this_thread::get_id() << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "Leave thread: " << std::this_thread::get_id() << std::endl;
g_io_mutex.unlock();
}
static void Test1() {
std::thread threads[10];
for (std::thread& thread : threads) {
thread = std::thread(Func1);
}
for (std::thread& thread : threads) {
thread.join();
}
}
//------------------------------------------------------------------------
template<typename T>
class Container {
public:
void Add(const T& element) {
mutex_.lock();
elements_.push_back(element);
mutex_.unlock();
}
// 2.同一個線程多次去擷取已經被該線程擷取的mutex鎖,如果使用std::mutex就會導緻程式進入死鎖。
// (A)解決辦法可以使用std::recursive_mutex遞歸互斥量。
// std::recursive_mutex 與 std::mutex 一樣,也是一種可以被上鎖的對象,但是和 std::mutex 不同的是,
// std::recursive_mutex 允許同一個線程對用一個互斥量多次上鎖(即遞歸上鎖),來獲得對互斥量對象的多層所有權,
// std::recursive_mutex 釋放互斥量時需要調用與該鎖層次深度相同次數的 unlock(),可了解為 lock() 次數和 unlock() 次數相同。
// 而std::mutex效率更高。
void AddForTestRecursive(const T& element) {
mutex_.lock();
Add(element);
mutex_.unlock();
}
void Dump() const {
mutex_.lock();
for (const T& element : elements_) {
std::cout << element << std::endl;
}
mutex_.unlock();
}
private:
std::list<T> elements_;
//std::mutex mutex_; // 導緻死鎖。
//std::recursive_mutex mutex_; // 編譯錯誤,因為Dump是const的,而函數中調用的mutex_的lock和unlock是非const的。
// (B)mutable是為了突破const的限制而設定的。被mutable修飾的變量,将永遠處于可變的狀态,即使在一個const函數中,
// 甚至結構體變量或者類對象為const,其mutable成員也可以被修改。
mutable std::recursive_mutex mutex_;
};
static void Func2(Container<int>& container, int start, int end) {
for (int i = start; i <= end; ++i) {
container.AddForTestRecursive(i);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
static void Test2() {
Container<int> container;
std::thread thread1(Func2, std::ref(container), 1, 10);
std::thread thread2(Func2, std::ref(container), 100, 110);
thread1.join();
thread2.join();
container.Dump();
}
//------------------------------------------------------------------------
// 3.區域鎖
// 區域鎖lock_guard使用起來比較簡單,除了構造函數外沒有其他member function,在整個區域都有效。
// 區域鎖unique_guard除了lock_guard的功能外,提供了更多的member_function,相對來說更靈活一些。
static void Func3() {
std::unique_lock<std::mutex> lock(g_io_mutex);
std::cout << "Enter thread: " << std::this_thread::get_id() << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "Leave thread: " << std::this_thread::get_id() << std::endl;
}
static void Test3() {
std::thread threads[10];
for (std::thread& thread : threads) {
thread = std::thread(Func3);
}
for (std::thread& thread : threads) {
thread.join();
}
}
} // namespace thread_lock
//------------------------------------------------------------------------
int main() {
Test1();
//Test2();
//Test3();
return 0;
}