一.線程執行體:
Lambda表達式的多線程
#include<iostream>
#include<thread>
#include<vector>
#include<algorithm>
using namespace std;
int main() {
thread td([](int a, int b) {
cout << a << "+" << b << "=" << a + b << endl;
},1,2);
td.join();
system("pause");
}
對象的多線程
struct functor
{
void operator()(int a, int b) {
cout << a << "+" << b << "=" << a + b << endl;
}
};
int main() {
thread td(functor(),1,2);
td.join();
system("pause");
}
使用std::bind表達式綁定對象和其非靜態成員函數
using namespace std;
class C {
int data_;
public:
C(int data) :data_(data) {}
void member_fun(int c) {
cout << "this->data=" << this->data_ << "; extend c=" << c << endl;
}
};
int main() {
C obj(10);
thread td(bind(&C::member_fun, &obj,3));
td.join();
system("pause");
}
使用Lambda表達式調用對象的非靜態成員函數
class C {
public:
int data_;
C(int data) :data_(data) {}
void member_fun(int c) {
cout << "this->data=" << this->data_ << "; extend c=" << c << endl;
}
};
int main() {
C obj(10);
auto a = [obj]()mutable {obj.member_fun(3); };
obj.data_ = 11;
thread td(a);
td.join();
thread td2([&obj]() {obj.member_fun(4); });
td2.join();
system("pause");
}
注意結果的輸出,兩種lambda策略,上面一種是複製obj,下面是引用。所以打印時一個是10,一個是11
二.線程管理函數
1.
#include <iostream>
#include <thread>
#include <iomanip>
int main()
{
std::thread td([](){});
std::cout << "td.joinable() = " << std::boolalpha << td.joinable() << std::endl;
td.detach();
std::cout << "td.joinable() = " << std::boolalpha << td.joinable() << std::endl;
}
2.
#include <iostream>
#include <thread>
#include <iomanip>
int main()
{
std::thread td([](){});
std::cout << "td.joinable() = " << std::boolalpha << td.joinable() << std::endl;
td.join();
std::cout << "td.joinable() = " << std::boolalpha << td.joinable() << std::endl;
}
3.RAII
class thread_guard {
std::thread& t_;
public:
explicit thread_guard(std::thread& t) : t_(t) { }
thread_guard(const thread_guard&) =delete;
thread_guard& operator=(const thread_guard&) =delete;
~thread_guard() { if (t_.joinable()) t_.join(); }
};
三.互斥Mutex
std::mutex 互斥對象
std::timed_mutex 帶有超時的互斥,超時後直接放棄
std::recusive_mutex 允許被同一個程序遞歸的lock unlock
std::recusive_timed_mutex 帶了超時的xx
std::shared_timed_mutex(c++14) 允許多個線程共享所有權的互斥對象,比如讀寫鎖
用mutex對set的insert操作進行保護,實現安全的併發訪問
#include<iostream>
#include<thread>
#include<vector>
#include<algorithm>
#include "ThreadGuard.h"
#include <set>
#include <mutex>
#include<random>
int main() {
std::set<int> int_set;
std::mutex mt;
auto f = [&int_set, &mt]() {
try {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(1, 1000);
for (std::size_t i = 0; i != 100000; ++i) {
mt.lock();
int_set.insert(dis(gen));
mt.unlock();
}
}
catch (...) {}
};
std::thread td1(f), td2(f);
td1.join();
td2.join();
system("pause");
}
四.使用RAII管理互斥對象
std::lock_guar 嚴格基於作用域的鎖管理類模板,構造時是否加鎖是可選的,析構時自動釋放鎖,所有權不可轉移,對象生存期內不允許手動加鎖和釋放鎖
std::unique_lock 更加靈活的鎖管理模板,構造時是否加鎖可選,在對象析構時如果持有鎖會自動釋放鎖,所有權可以轉移。對象生命週期允許手動加鎖和釋放鎖
std::shared——lock(c++14)
int main() {
std::set<int> int_set;
std::mutex mt;
auto f = [&int_set, &mt]() {
try {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(1, 1000);
for (std::size_t i = 0; i != 100000; ++i) {
std::lock_guard < std::mutex> lck(mt);
int_set.insert(dis(gen));
}
}
catch (...) {}
};
std::thread td1(f), td2(f);
td1.join();
td2.join();
system("pause");
}
加鎖策略:
1.默認 請求鎖,阻塞當前線程直到成功獲得鎖 三種都支撐
2.std::defer_lock 不請求鎖 unique_lock,shared_lock
3.std::try_to_lock 嘗試請求鎖,但不阻塞線程,鎖不可用時也會立即返回 unique_lock,shared_lock
4.std::adopt_lock 假定當前線程已經獲得互斥對象的所有權,所以不再請求鎖 lock_guard,unique_lock,shared_lock
{
std::unique_lock<std::mutex> lock1(mutex1, std::defer_lock);
std::unique_lock<std::mutex> lock2(mutex2, std::defer_lock);
std::lock(mtx1, mtx2);
do_sth();
}
{
std::lock(mtx1, mtx2);
std::lock_guard<std::mutex> lock1(mutex1, std::adopt_lock);
std::lock_guard<std::mutex> lock2(mutex2, std::adopt_lock);
do_sth();
}
{
std::unique_lock<std::mutex> lock1(mutex1, std::try_to_lock);
if(lock1.owns_lock()){
do_sth1();
} esle {
do_sth2();
}
}