C++ 多線程(一)

C++ 多線程(一)

  • 1.std中的thread API 介紹
    • 開啟一個線程
    • 獲取線程信息API
    • 交換兩個線程
  • 2.向線程里傳遞參數的方法
    • 第一種方式(在創建線程的構造函數后攜帶參數)
    • 第二種方式(Lambda)
    • 第三種方式(成員函數)
  • 3.互斥鎖
  • 4.try_lock
  • 5.掛起和喚醒線程
  • 6.將主線程資源移動到其他線程
  • 7.lock_guard
  • 8.unique_lock
  • 9.call_once
  • 10.condition_variable


1.std中的thread API 介紹

開啟一個線程

如下是定義一個線程

std::thread Thread1(ThreadFunc1)

其開始運行有兩種方式,一個是阻塞當前調用進程,一個是異步的方式不會阻塞當前調用的進程

join會阻塞當前調用的進程

Thread1.join()

detach不會阻塞當前調用進程

Thread1.detach()

獲取線程信息API

獲取線程ID

Thread1.get_id()

判斷線程是否是可啟用的

Thread1.joinable() 

這樣輸出的值是true

	std::thread Thread1(ThreadFunc1);cout << Thread1.joinable() << endl;

如果傳入的執行參數為空則是不可啟用

	std::thread Thread1;cout << Thread1.joinable() << endl;

如果想獲取計算機能創建的線程數

Thread1.hardware_concurrency()

獲取當前線程ID

 std::this_thread::get_id()

使當前線程睡眠n秒
有兩種方式,一種是std的,一種是windows底層的

	std::this_thread::sleep_for(chrono::seconds(2));

注意windows的睡眠需要引用頭文件Windows.h

#include <Windows.h>
Sleep(1000);

交換兩個線程

std::thread Thread1(ThreadFunc1)
std::thread Thread2(ThreadFunc2)
Thread1.spawn(Thread2)

2.向線程里傳遞參數的方法

先定義要在子線程執行的方法

void Func1(int a, const string& b)
{cout << a << endl;cout << b << endl;
}

第一種方式(在創建線程的構造函數后攜帶參數)

	std::thread NewThread1(Func1, 1, "Hello");NewThread1.join();

第二種方式(Lambda)

	int a = 100;std::thread NewThread2([&](int value1,const string& value2){cout << "=====================" << endl;cout << a << endl;cout << value1 << endl;cout << value2 << endl;},2,"World");NewThread2.join();

第三種方式(成員函數)

class FTestClass
{
public:void Run(int a,const string& b){cout << a << endl;cout << b << endl;}
};
	FTestClass TestClass;std::thread NewThread3(&FTestClass::Run, &TestClass, 3, "TestClass");NewThread3.join();

3.互斥鎖

為了避免多線程之間的資源競爭自然需要這種互斥的鎖

使用前需要引用頭文件

#include <mutex>
mutex mx;
void NewThreadFunc()
{mx.lock();cout << "等待2s" << endl;std::this_thread::sleep_for(chrono::seconds(2));mx.unlock();
}
	for (size_t i = 0; i < 5; i++){std::thread th(NewThreadFunc5);th.detach();}

最后我們會發現每隔2s輸出一次信息

我們每次使用鎖都需要lock 和 unlock 這是十分不便利的,而且如果我們忘記解鎖就會死鎖
我們可以使用析構來實現這種自動解鎖的方式

struct FEvent
{FEvent(){m.lock();}~FEvent(){m.unlock();}static mutex m;
};
mutex FEvent::m;

再使用宏包裹一下

#define LOCK_TEST FEvent LockEvent;

如下是在線程執行的函數,只需要定義一行就可以自動解鎖

void NewThreadFunc()
{LOCK_TESTcout << "等待2s" << endl;std::this_thread::sleep_for(chrono::seconds(2));
}

4.try_lock

try_lock 返回bool 值,是否能上鎖

static mutex mx;
void NewThreadFunc2()
{if (mx.try_lock()){cout << "等待2s" << endl;std::this_thread::sleep_for(chrono::seconds(2));mx.unlock();}else {cout << "鎖被使用" << endl;}
}
	for (size_t i = 0; i < 5; i++){std::thread NewThread2(NewThreadFunc2);NewThread2.detach();}

最后輸出我們會發現只打印了一個等待2s 和四個鎖被使用

5.掛起和喚醒線程

定義在子線程執行的函數

void NewThreadFunc3()
{while (true){Sleep(1000);cout << "Hello" << endl;}
}

SuspendThread 用于掛起線程
ResumeThread 用于喚醒線程

	std::thread th(NewThreadFunc3);SuspendThread(th.native_handle());std::this_thread::sleep_for(chrono::seconds(2));ResumeThread(th.native_handle());

6.將主線程資源移動到其他線程

定義在子線程執行的函數

void NewThreadFunc4(const string& Value)
{cout << Value << endl;
}
	std::thread th1(NewThreadFunc4,move("Hello world"));std::thread th2 = move(th1);th2.detach();

將th1的所有權轉移給th2。此時,th1不再代表任何線程(相當于th1處于“空”狀態),而th2現在代表原來th1所代表的線程。這是因為std::thread是不可復制的,但可以移動。所以,這里通過移動賦值(或移動構造)將th1的線程所有權轉移給th2。

7.lock_guard

類似我們之前自己封裝的自動解鎖的鎖,不要手動調用unlock,函數執行完畢自動析構

mutex mx;
void NewThreadFunc5()
{lock_guard<mutex> lock(mx);cout << "Hello world" << endl;Sleep(2000);
}
	for (size_t i = 0; i < 5; i++){std::thread th(NewThreadFunc5);th.detach();}

每隔2s輸出一次一共輸出了5次

8.unique_lock

unique_lock 相對于上面的 lock_guard 多了更多的功能API 可以更自由豐富的操作鎖

defer_lock 此參數是延時的意思,鎖并不是立馬生效,需要手動lock

unique_lock 也是過了作用域會自動解鎖

static mutex mt;
void Func1()
{unique_lock<mutex> lock1(mt,defer_lock);// 不需要上鎖的函數cout << "這是不需要上鎖的函數" << endl;lock1.lock();cout << "這是需要上鎖的函數" << endl;lock1.unlock();//lock2.try_lock_until(); 鎖到某個時間點//lock2.release(); 釋放//lock2.mutex();拿到鎖本體//lock2.swap(); 交換//lock2.owns_lock(); 判斷是否鎖住
}

下面演示一個unique_lock 的 try_lock_for()方法

static timed_mutex timeMt;
void Func2()
{unique_lock<timed_mutex> lock2(timeMt, defer_lock);if (lock2.try_lock_for(chrono::seconds(2))){cout << "鎖住2s后" << endl;this_thread::sleep_for(chrono::seconds(1));}else{cout << "鎖正在被占用" << endl;}
}
	for (size_t i = 0; i < 5; i++){thread th(Func2);th.detach();}

我們會發現輸出了2個鎖住2s后和3個鎖正在被占用,是因為這個鎖定義了鎖住的時間為2s,當第一次運行后只執行了1s第二次進入仍然沒超過定義的鎖的2s所以可以進入,而之后都超過2s了,故無法進入了。

9.call_once

顧名思義就是無論調用多少次只執行一次

once_flag oneFlag;
void Func3()
{call_once(oneFlag, [](){cout << "運行一次" << endl;});
}
	for (size_t i = 0; i < 5; i++){Func3();}

10.condition_variable

條件變量,一個地方可以等待直到通知這個等待就可以執行等待之后的代碼

mutex tx1;
condition_variable cv;
void Func4()
{Sleep(1000);cv.notify_one();Sleep(1000);
}
	std::thread th(Func4);th.detach();unique_lock<mutex> Lock1(tx1);cv.wait(Lock1);cout << "運行Wait之后" << endl;

notify_one 是一個,還有多個版本notify_all

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/916435.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/916435.shtml
英文地址,請注明出處:http://en.pswp.cn/news/916435.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

自動駕駛訓練-tub詳解

在 Donkeycar 的環境里&#xff0c;“tub” 是一個很關鍵的術語&#xff0c;它代表的是存儲訓練數據的目錄。這些數據主要來源于自動駕駛模型訓練期間收集的圖像和控制指令。 Tub 的構成 一個標準的 tub 目錄包含以下兩類文件&#xff1a; JSON 記錄文件&#xff1a;其命名格式…

CVPR多模態破題密鑰:跨模對齊,信息串供

關注gongzhonghao【CVPR頂會精選】當今數字化時代&#xff0c;多模態技術正迅速改變我們與信息互動的方式。多模態被定義為在特定語境中多種符號資源的共存與協同。這種技術通過整合不同模態的數據&#xff0c;如文本、圖像、音頻等&#xff0c;為用戶提供更豐富、更自然的交互…

小米路由器3G R3G 刷入Breed和OpenWrt 插入可共享網絡的usb隨身WiFi

小米 R3G 參數&#xff08;以下加黑加粗需要特別關注&#xff0c;灰常詳細&#xff09; 市面上有R3G和R3Gv2兩種型號, 注意區分, 后者是縮水版, 沒有USB口. 內存只有128M, Flash只有16M. 這里描述的只適用于R3G. 就是這樣 操作步驟開始&#xff0c;&#xff0c;注&#xff1a…

SpringBoot實現Serverless:手擼一個本地函數計算引擎

前言 最近突然冒出一個想法&#xff1a;能不能用SpringBoot自己實現一個類似AWS Lambda或阿里云函數計算的執行引擎&#xff1f; 說干就干&#xff0c;于是從零開始設計了一套基于SpringBoot的Serverless執行框架。 這套框架支持函數動態加載、按需執行、資源隔離&#xff0c;甚…

Java排序算法之<插入排序>

目錄 1、插入排序 2、流程介紹 3、java實現 4、性能介紹 前言 在 Java 中&#xff0c; 冒泡排序&#xff08;Bubble Sort&#xff09; 和 選擇排序&#xff08;Selection Sort&#xff09; 之后&#xff0c;下一個性能更好的排序算法通常是 插入排序&#xff08;Insertion …

《計算機網絡》實驗報告七 HTTP協議分析與測量

目 錄 1、實驗目的 2、實驗環境 3、實驗內容 4、實驗結果與分析 4.1 使用tcpdump命令抓包 4.2 HTTP字段分析 5、實驗小結 5.1 問題與解決辦法&#xff1a; 5.2 心得體會&#xff1a; 1、實驗目的 1、了解HTTP協議及其報文結構 2、了解HTTP操作過程&#xff1a;TCP三次…

面試實戰,問題十三,Redis在Java項目中的作用及使用場景詳解,怎么回答

Redis在Java項目中的作用及使用場景詳解&#xff08;面試要點&#xff09; 一、Redis的核心作用高性能緩存層 原理&#xff1a;Redis基于內存操作&#xff08;引用[2]&#xff09;&#xff0c;采用單線程模型避免線程切換開銷&#xff0c;配合IO多路復用實現高吞吐&#xff08;…

Python - 100天從新手到大師 - Day6

引言 這里主要是依托于 jackfrued 倉庫 Python-100-Days 進行學習&#xff0c;記錄自己的學習過程和心得體會。 1 文件讀寫和異常處理 實際開發中常常會遇到對數據進行持久化的場景&#xff0c;所謂持久化是指將數據從無法長久保存數據的存儲介質&#xff08;通常是內存&…

IP--MGER綜合實驗報告

一、實驗目的完成網絡設備&#xff08;路由器 R1-R5、PC1-PC4&#xff09;的 IP 地址規劃與配置&#xff0c;確保接口通信基礎正常。配置鏈路層協議及認證&#xff1a;R1 與 R5 采用 PPP 的 PAP 認證&#xff08;R5 為主認證方&#xff09;&#xff0c;R2 與 R5 采用 PPP 的 CH…

window的WSL怎么一鍵重置

之前用WSL來在windows和服務器之間傳輸數據&#xff0c;所以有很多數據緩存&#xff0c;但是現在找不到他們的路徑&#xff0c;所以想直接重置 首先使用spacesniffer看一下C盤的情況&#xff1a;看起來&#xff0c;這個WSL真的占用了很多空間&#xff0c;但是我又不知道該怎么刪…

卷積神經網絡研討

卷積操作原理: 特征向量與遍歷:假設已知特征向量(如藍天白云、綠油油草地特征),在輸入圖像的各個區域進行遍歷,通過計算內積判斷該區域是否有想要的特征。 內積計算特征:內積為 0 表示兩個向量垂直,關系不好,無想要的特征;夾角越小,內積越大,代表區域中有想要的特征…

【EWARM】EWARM(IAR)的安裝過程以及GD32的IAR工程模板搭建

一、簡介 IAR官網 EWARM&#xff0c;即 IAR Embedded Workbench for ARM&#xff0c;是由 IAR Systems 開發的一款專門用于 ARM 微處理器軟件開發的集成開發環境。以下是具體介紹&#xff1a; 功能特性&#xff1a; 完整工具鏈支持&#xff1a;集成了高級編輯器、全面的編譯…

【工程化】淺談前端構建工具

一、前端構建工具概述? 前端構建工具是輔助開發者將源代碼轉換為瀏覽器可直接運行的靜態資源的工具集合。隨著前端技術的發展&#xff0c;源代碼往往包含瀏覽器無法直接解析的語法&#xff08;如 TypeScript、Sass&#xff09;、模塊化規范&#xff08;如 ES Modules、Common…

數據取證:Elcomsoft Password Digger,解密 macOS (OS X) 鑰匙串信息

Elcomsoft Password Digger&#xff08;EPD&#xff09;是一款在 Windows 平臺上使用的工具&#xff0c;用于解密存儲在 macOS 鑰匙串中的信息。該工具可以將加密的鑰匙串內容導出到一個純文本 XML 文件中&#xff0c;方便查看和分析。一鍵字典構建功能可以將鑰匙串中的所有密碼…

2.JVM跨平臺原理(字節碼機制)

目錄引言一、跨平臺就跟國際語言翻譯似的二、字節碼和 JVM 到底是啥玩意兒三、解決 “語言不通” 這個老難題四、實現 “一次編寫&#xff0c;到處運行” 就這四步五、字節碼技術給世界帶來的大改變總結引言 咱平常是不是老納悶兒&#xff0c;為啥同一個 Java 程序&#xff0c…

06-ES6

微任務&宏任務JS是單線程執行。所有要執行的任務都要排隊。所有的同步任務會在主線程上排隊&#xff0c;等待執行。異步任務&#xff1a;不會進入主線程&#xff0c;而是會進入任務隊列。等到主線程上的任務執行完成之后&#xff0c;通知任務隊列&#xff0c;執行異步任務。…

FreeSWITCH配置文件解析(10) 配置IP封禁(防暴力破解)

以下是針對FreeSWITCH配置IP封禁&#xff08;防暴力破解&#xff09;的完整方案&#xff0c;結合Fail2Ban與系統級防護策略&#xff1a;一、Fail2Ban核心配置&#xff08;推薦方案&#xff09;??啟用FreeSWITCH鑒權日志??修改SIP Profile&#xff08;conf/sip_profiles/int…

【React 入門系列】React 組件通訊與生命周期詳解

&#x1f9e9; 第一章&#xff1a;組件通訊概述在 React 開發中&#xff0c;組件是封裝的、獨立的功能單元。為了實現組件間的數據共享與協作&#xff0c;需要通過組件通訊機制。組件通訊的意義&#xff1a; 讓多個封閉的組件能夠共享數據&#xff0c;實現協作功能。&#x1f4…

前端開發 Vue 狀態優化

Vue 項目中的狀態優化一般都會用Pinia替代Vuex&#xff0c;Pinia 是 Vue 生態系統中的一個輕量級狀態管理庫&#xff0c;作為 Vuex 的替代品&#xff0c;它提供了更簡潔的 API 和更好的性能。模塊化管理&#xff1a;使用 Pinia 時&#xff0c;建議將狀態拆分為多個 store 模塊&…

虛幻基礎:創建角色——FPS

能幫到你的話&#xff0c;就給個贊吧 &#x1f618; 文章目錄創建角色設置模型添加攝像機添加位置&#xff1a;插槽彈簧臂&#xff1a;伸縮防止由碰撞導致攝像機穿模攝像機添加武器添加位置&#xff1a;插槽創建動畫藍圖&#xff1a;主動獲取角色數據并播放相應動畫設置角色控制…