Linux:VMware 搭建虛擬機器 - CentOS 7
阿新 • • 發佈:2022-05-07
參考連結: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));
}
}