1. 程式人生 > 其它 >Linux:VMware 搭建虛擬機器 - CentOS 7

Linux:VMware 搭建虛擬機器 - CentOS 7

參考連結:https://www.cnblogs.com/zizbee/p/13520823.html

c++建立執行緒的方式

需要包含標頭檔案#include <thread>

// 準備用於建立執行緒的函式
void proc(int a) {
	std::cout << "我是子執行緒" << std::this_thread::get_id() << ",傳入引數為" << a << std::endl;
	std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	std::cout << "子執行緒" << std::this_thread::get_id() << "結束" << std::endl;
}

int main(){
	std::cout << "我是主執行緒" << std::endl;
    thread th(proc,9); // 建立執行緒
    th.join(); // 主執行緒阻塞的,等待th執行緒執行結束主執行緒再繼續
	std::cout << "主執行緒" << std::this_thread::get_id() << "結束" << std::endl;
	return 0;
}

// 注意:只要建立了執行緒物件(傳遞“函式名/可呼叫物件”作為引數的情況下),執行緒就開始執行(std::thread 有一個無參建構函式過載的版本,不會建立底層的執行緒)。

多執行緒經典案例:買票

同時開啟多個執行緒進行購票,如果不加鎖就會出現以下情況:

程式碼:

#include <thread>
#include <iostream>
#include <vector>

int ticket_num_left = 10; // 一共10張票

void buy_ticket(int id) {
	while (true) {
		if (ticket_num_left > 0) {
			std::this_thread::sleep_for(std::chrono::milliseconds(30));
			ticket_num_left--;
			std::cout << "執行緒" << id << "買了一張票,現在還剩" << ticket_num_left << "張票" << std::endl;
		}
		else {
			std::cout << "執行緒" << id << "無票可買" << std::endl;
			break;
		}
		std::this_thread::sleep_for(std::chrono::milliseconds(30));
	}
}

int main() {
	std::cout << "我是主執行緒" << std::endl;
	std::vector<std::thread*> threads;

    // 同時開啟9個執行緒一起買票
	for (int i = 0; i < 9; i++) {
		std::thread* th_ptr = new std::thread(buy_ticket, i + 1);
		threads.push_back(th_ptr);
	}

	for (std::vector<std::thread*>::iterator it = threads.begin(); it != threads.end(); it++) {
		(*it)->join();
	}

	std::cout << "主執行緒" << std::this_thread::get_id() << "結束" << std::endl;
	return 0;
}

執行結果如下,出現奇怪的票數:

我是主執行緒
執行緒5買了一張票,現在還剩2張票
執行緒2買了一張票,現在還剩2張票
執行緒9買了一張票,現在還剩2張票
執行緒8買了一張票,現在還剩2張票
執行緒1買了一張票,現在還剩2張票
執行緒3買了一張票,現在還剩2張票
執行緒7買了一張票,現在還剩2張票
執行緒6買了一張票,現在還剩2張票
執行緒4買了一張票,現在還剩2張票
執行緒2買了一張票,現在還剩-1張票
執行緒9買了一張票,現在還剩-1張票
執行緒5買了一張票,現在還剩-1張票
執行緒7買了一張票,現在還剩-7張票
執行緒1買了一張票,現在還剩-7張票
執行緒4買了一張票,現在還剩-7張票
執行緒3買了一張票,現在還剩-7張票
執行緒8買了一張票,現在還剩-7張票
執行緒6買了一張票,現在還剩-7張票
執行緒2無票可買
執行緒5無票可買
執行緒9無票可買
執行緒3無票可買
執行緒6無票可買
執行緒8無票可買
執行緒7無票可買
執行緒1無票可買
執行緒4無票可買
主執行緒23060結束

原因分析:

解決方法:單個執行緒在購票時,使用互斥量加鎖

#include <mutex>

方法一:lock()與unlock()

程式碼:

#include <thread>
#include <iostream>
#include <vector>
#include <mutex>

int ticket_num_left = 10;
std::mutex mutex_;

void buy_ticket(int id) {
	while (true) {
		mutex_.lock();
		if (ticket_num_left > 0) {
			std::this_thread::sleep_for(std::chrono::milliseconds(30));
			ticket_num_left--;
			std::cout << "執行緒" << id << "買了一張票,現在還剩" << ticket_num_left << "張票" << std::endl;
		}
		else {
			std::cout << "執行緒" << id << "無票可買" << std::endl;
			mutex_.unlock();
			break;
		}
		mutex_.unlock();
		std::this_thread::sleep_for(std::chrono::milliseconds(30));
	}
}

int main() {
	std::cout << "我是主執行緒" << std::endl;
	std::vector<std::thread*> threads;

	for (int i = 0; i < 9; i++) {
		std::thread* th_ptr = new std::thread(buy_ticket, i + 1);
		threads.push_back(th_ptr);
	}

	for (std::vector<std::thread*>::iterator it = threads.begin(); it != threads.end(); it++) {
		(*it)->join();
	}

	std::cout << "主執行緒" << std::this_thread::get_id() << "結束" << std::endl;
	return 0;
}

執行結果:

我是主執行緒
執行緒2買了一張票,現在還剩9張票
執行緒1買了一張票,現在還剩8張票
執行緒3買了一張票,現在還剩7張票
執行緒4買了一張票,現在還剩6張票
執行緒5買了一張票,現在還剩5張票
執行緒6買了一張票,現在還剩4張票
執行緒7買了一張票,現在還剩3張票
執行緒8買了一張票,現在還剩2張票
執行緒9買了一張票,現在還剩1張票
執行緒2買了一張票,現在還剩0張票
執行緒1無票可買
執行緒3無票可買
執行緒4無票可買
執行緒5無票可買
執行緒6無票可買
執行緒7無票可買
執行緒8無票可買
執行緒9無票可買
執行緒2無票可買
主執行緒17224結束

方法二:lock_guard()

建立即加鎖,作用域結束自動解鎖。

程式碼:

#include <thread>
#include <iostream>
#include <vector>
#include <mutex>

int ticket_num_left = 10;
std::mutex mutex_;

void buy_ticket(int id) {
	while (true) {
		std::lock_guard<std::mutex> lockGuard(mutex_); // 用lock_guard替代lock和unlock
		//mutex_.lock();
		if (ticket_num_left > 0) {
			std::this_thread::sleep_for(std::chrono::milliseconds(30));
			ticket_num_left--;
			std::cout << "執行緒" << id << "買了一張票,現在還剩" << ticket_num_left << "張票" << std::endl;
		}
		else {
			std::cout << "執行緒" << id << "無票可買" << std::endl;
			//mutex_.unlock();
			break;
		}
		//mutex_.unlock();
		std::this_thread::sleep_for(std::chrono::milliseconds(30));
	}
}

int main() {
	std::cout << "我是主執行緒" << std::endl;
	std::vector<std::thread*> threads;

	for (int i = 0; i < 9; i++) {
		std::thread* th_ptr = new std::thread(buy_ticket, i + 1);
		threads.push_back(th_ptr);
	}

	for (std::vector<std::thread*>::iterator it = threads.begin(); it != threads.end(); it++) {
		(*it)->join();
	}

	std::cout << "主執行緒" << std::this_thread::get_id() << "結束" << std::endl;
	return 0;
}

方法三:unique_lock

unique_lock類似於lock_guard,只是unique_lock用法更加豐富,同時支援lock_guard()的原有功能。
使用lock_guard後不能手動lock()與手動unlock();使用unique_lock後可以手動lock()與手動unlock();
unique_lock的第二個引數,除了可以是adopt_lock,還可以是try_to_lock與defer_lock;
try_to_lock: 嘗試去鎖定,得保證鎖處於unlock的狀態,然後嘗試現在能不能獲得鎖;嘗試用mutx的lock()去鎖定這個mutex,但如果沒有鎖定成功,會立即返回,不會阻塞在那裡
defer_lock: 始化了一個沒有加鎖的mutex;

lock_guard unique_lock
手動lock與手動unlock 不支援 支援
引數 支援adopt_lock 支援adopt_lock/try_to_lock/defer_lock

詳見連結:https://www.cnblogs.com/zizbee/p/13520823.html

void buy_ticket(int id) {
	while (true) {
		std::unique_lock<std::mutex> deferLock(mutex_, std::defer_lock);//始化了一個沒有加鎖的mutex
		//std::lock_guard<std::mutex> lockGuard(mutex_);
		//mutex_.lock();
		deferLock.lock();
		if (ticket_num_left > 0) {
			std::this_thread::sleep_for(std::chrono::milliseconds(30));
			ticket_num_left--;
			std::cout << "執行緒" << id << "買了一張票,現在還剩" << ticket_num_left << "張票" << std::endl;
		}
		else {
			std::cout << "執行緒" << id << "無票可買" << std::endl;
			//mutex_.unlock();
			deferLock.unlock();
			break;
		}
		//mutex_.unlock();
		deferLock.unlock();
		std::this_thread::sleep_for(std::chrono::milliseconds(30));
	}
}