C++多線程學習筆記

一.線程執行體:

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();
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章