日B视频 亚洲,啪啪啪网站一区二区,91色情精品久久,日日噜狠狠色综合久,超碰人妻少妇97在线,999青青视频,亚洲一区二卡,让本一区二区视频,日韩网站推荐

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

co_await這些協(xié)程時需要注意線程切換的細節(jié)

程序喵大人 ? 來源:程序喵大人 ? 作者:程序喵大人 ? 2022-11-03 09:18 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

bfc58fd8-5b13-11ed-a3b6-dac502259ad0.png

在異步操作里,如異步連接、異步讀寫之類的協(xié)程,co_await這些協(xié)程時需要注意線程切換的細節(jié)。

以asio異步連接協(xié)程為例:

classclient{
public:
client(){
thd_=std::thread([this]{
io_ctx_.run();
});
}

async_simple::Lazyasync_connect(autohost,autoport){
boolret=co_awaitutil::async_connect(host,port);#1
co_returnret;#2
}

~client(){
io_ctx_.stop();
if(thd_.joinable()){
thd_.join();
}
}

private:
asio::io_contextio_ctx_;
std::threadthd_;
};

intmain(){
clientc;
async_simple::syncAwait(c.async_connect());
std::cout<<"quit
";#3
}

這個例子很簡單,client在連接之后就析構(gòu)了,看起來沒什么問題。但是運行之后就會發(fā)生線程join的錯誤,錯誤的意思是在線程里join自己了。這是怎么回事?co_await一個異步連接的協(xié)程,當連接成功后協(xié)程返回,這時候發(fā)生了線程切換。異步連接返回的時候是在io_context的線程里,代碼中的#1在主線程,#2在io_context線程,之后就co_return 返回到main函數(shù)的#3,這時候#3仍然在io_context線程里,接著client就會析構(gòu)了,這時候仍然在io_context線程里,析構(gòu)的時候會調(diào)用thd_.join(); 然后就導致了在io_context的線程里join自己的錯誤。

這是使用協(xié)程時容易犯錯的一個地方,解決方法就是避免co_await回來之后去析構(gòu)client,或者co_await回來仍然回到主線程。這里可以考慮用協(xié)程條件變量,在異步連接的時候發(fā)起一個新的協(xié)程并傳入?yún)f(xié)程條件變量并在連接返回后set_value,主線程去co_await這個條件變量,這樣連接返回后就回到主線程了,就可以解決在io線程里join自己的問題了。

bfc58fd8-5b13-11ed-a3b6-dac502259ad0.png

還是以上面的異步連接為例子,需要對之前的async_connect協(xié)程增加一個超時功能,代碼稍作修改:

classclient{
public:
client():socket_(io_ctx_){
thd_=std::thread([this]{
io_ctx_.run();
});
}

async_simple::Lazyasync_connect(autohost,autoport,autoduration){
coro_timertimer(io_ctx_);
timeout(timer,duration).start([](auto&&){});//#1啟動一個新協(xié)程做超時處理
boolret=co_awaitutil::async_connect(host,port,socket_);//假設這里co_await返回后回到主線程
co_returnret;
}

~client(){
io_ctx_.stop();
if(thd_.joinable()){
thd_.join();
}
}


private:
async_simple::Lazytimeout(auto&timer,autoduration){
boolis_timeout=co_awaittimer.async_wait(duration);
if(is_timeout){
asio::error_codeignored_ec;
socket_.shutdown(tcp::shutdown_both,ignored_ec);
socket_.close(ignored_ec);
}

co_return;
}

asio::io_contextio_ctx_;
tcp::socketsocket_;
std::threadthd_;
boolis_timeout_;
};

intmain(){
clientc;
async_simple::syncAwait(c.async_connect("localhost","9000",5s));
std::cout<<"quit
";#3
}

這個代碼增加連接超時處理的協(xié)程,注意#1那里為什么需要新啟動一個協(xié)程,而不能用co_await呢?因為co_await是阻塞語義,co_await會導致永遠超時,啟動一個新的協(xié)程不會阻塞當前協(xié)程從而可以去調(diào)用async_connect。

當timeout超時發(fā)生時就關(guān)閉socket,這時候async_connect就會返回錯誤然后返回到調(diào)用者,這看起來似乎可以對異步連接做超時處理了,但是這個代碼是有問題的。假如異步連接沒有超時會發(fā)生什么?沒有超時的話就返回到main函數(shù)了,然后client就析構(gòu)了,當timeout協(xié)程resume回來的時候client其實已經(jīng)析構(gòu)了,這時候再去調(diào)用成員變量socket_ close將會導致一個訪問已經(jīng)析構(gòu)對象的錯誤。

也許有人會說,那就在co_return之前去取消timer不就好了嗎?這個辦法也不行,因為取消timer,timeout協(xié)程并不會立即返回,仍然會存在訪問已經(jīng)析構(gòu)對象的問題。

正確的做法應該是對兩個協(xié)程進行同步,timeout協(xié)程和async_connect協(xié)程需要同步,在async_connect協(xié)程返回之前需要確保timeout協(xié)程已經(jīng)完成,這樣就可以避免訪問已經(jīng)析構(gòu)對象的問題了。

這個問題其實也是異步回調(diào)安全返回的一個經(jīng)典問題,協(xié)程也同樣會遇到這個問題,上面提到的對兩個協(xié)程進行同步是解決方法之一,另外一個方法就是使用shared_from_this,就像異步安全回調(diào)那樣處理。

還是以異步連接為例:

async_simple::Lazyasync_connect(conststd::string&host,conststd::string&port){
co_returnco_awaitutil::async_connect(host,port);
}

async_simple::Lazytest_connect(){
boolok=co_awaitasync_connect("localhost","8000");
if(!ok){
std::cout<<"connectfailed
";
}

std::cout<<"connectok
";
}

intmain(){
async_simple::syncAwait(test_connect());
}

這個代碼簡單明了,就是測試一下異步連接是否成功,運行也是正常的。如果稍微改一下test_connect:

async_simple::Lazytest_connect(){
autolazy=async_connect("localhost","8000");
boolok=co_awaitlazy;
if(!ok){
std::cout<<"connectfailed
";
}

std::cout<<"connectok
";
}

很遺憾,這個代碼會導致連接總是失敗,似乎很奇怪,后面發(fā)現(xiàn)原因是因為async_connect的兩個參數(shù)失效了,但是寫法和剛開始的寫法幾乎一樣,為啥后面這種寫法會導致參數(shù)失效呢?

原因是co_await一個協(xié)程函數(shù)時,其實做了兩件事:

  • 調(diào)用協(xié)程函數(shù)創(chuàng)建協(xié)程,這個步驟會創(chuàng)建協(xié)程幀,把參數(shù)和局部變量拷貝到協(xié)程幀里;

  • co_await執(zhí)行協(xié)程函數(shù);

回過頭來看auto lazy = async_connect("localhost", "8000"); 這個代碼調(diào)用協(xié)程函數(shù)創(chuàng)建了協(xié)程,這時候拷貝到協(xié)程幀里面的是兩個臨時變量,在這一行結(jié)束的時候臨時變量就析構(gòu)了,在下一行去co_await執(zhí)行這個協(xié)程的時候就會出現(xiàn)參數(shù)失效的問題了。

co_await async_connect("localhost", "8000"); 這樣為什么沒問題呢,因為協(xié)程創(chuàng)建和協(xié)程調(diào)用都在一行完成的,臨時變量知道協(xié)程執(zhí)行之后才會失效,因此不會有問題。

問題的本質(zhì)其實是C++臨時變量生命周期的問題。使用協(xié)程的時候稍微注意一下就好了,可以把const std::string&改成std::string,這樣就不會臨時變量生命周期的問題了,如果不想改參數(shù)類型就co_await 協(xié)程函數(shù)就好了,不分成兩行去執(zhí)行協(xié)程。

審核編輯 :李倩


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 變量
    +關(guān)注

    關(guān)注

    0

    文章

    616

    瀏覽量

    29576
  • 線程
    +關(guān)注

    關(guān)注

    0

    文章

    510

    瀏覽量

    20875

原文標題:C++ 使用協(xié)程需要注意的問題

文章出處:【微信號:程序喵大人,微信公眾號:程序喵大人】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    微機消諧裝置在使用時需要注意什么

    ? ? ? ?微機消諧裝置在使用時需要注意什么?微機消諧裝置應安裝于PT開口三角處,消諧電阻器則置于PT一次側(cè)中性點與地之間。通過這種方式,裝置能夠有效地檢測并消除諧振現(xiàn)象,同時保護PT不受
    的頭像 發(fā)表于 03-16 11:44 ?150次閱讀

    變頻器清灰需要注意什么

    需要注意的要點,結(jié)合技術(shù)規(guī)范和實踐經(jīng)驗,為操作人員提供全面指導。 一、清灰前的準備工作 1. 斷電與放電 必須確保變頻器完全斷電,并等待至少10分鐘以上,使內(nèi)部電容充分放電。高壓電容殘留的電能可能高達數(shù)百伏,直接接
    的頭像 發(fā)表于 02-20 07:38 ?506次閱讀
    變頻器清灰<b class='flag-5'>需要注意</b>什么

    芯源MCU開發(fā)需要注意什么?

    芯源MCU開發(fā)需要注意什么
    發(fā)表于 01-04 12:04

    請問設備連接IIC通信接口需要注意什么?

    設備連接IIC通信接口需要注意什么?
    發(fā)表于 12-25 07:47

    使用RTOS時需要注意的幾點內(nèi)容分享

    是重入也可能是非重入的)外,各任務從不共享任何代碼。程序員(特別是那些負責設備驅(qū)動程序的)需要注意這一重入性問題。 現(xiàn)在業(yè)內(nèi)已有很多的任務同步機制,從互斥(mutex)到消息系統(tǒng)。從RTOS的角度
    發(fā)表于 12-23 06:34

    解析Linux的進程、線程和協(xié)

    )輕量級:相對于進程,線程的創(chuàng)建和切換開銷較小。 (3)同步與通信:線程之間需要通過同步機制(如互斥鎖、信號量)來保證數(shù)據(jù)的一致性。 協(xié)
    發(fā)表于 12-22 11:00

    高速PCB打樣必知:細節(jié)決定成敗,這些點你不能忽視!

    23年P(guān)CBA一站式行業(yè)經(jīng)驗PCBA加工廠家今天為大家講講高速pcb打樣需要注意什么細節(jié)?高速pcb打樣需要注意細節(jié)。在高速PCB(印刷電路板)打樣階段,為確保最終產(chǎn)品的性能和可靠性
    的頭像 發(fā)表于 12-16 09:19 ?468次閱讀
    高速PCB打樣必知:<b class='flag-5'>細節(jié)</b>決定成敗,<b class='flag-5'>這些</b>點你不能忽視!

    使用TTP233H-BA6時這6個細節(jié)要注意!

    的檢測性能,在消費電子領域得到了廣泛應用。然而,要想充分發(fā)揮其性能,在使用過程中需要注意以下幾個關(guān)鍵細節(jié)。一、靈敏度調(diào)節(jié)需精準TTP233H-BA6的靈敏度可通過電
    的頭像 發(fā)表于 12-10 17:41 ?1012次閱讀
    使用TTP233H-BA6時這6個<b class='flag-5'>細節(jié)</b><b class='flag-5'>要注意</b>!

    FreeRTOS任務和協(xié)的區(qū)別是什么

    1.堆棧 協(xié)是沒有堆棧分配的,是所有創(chuàng)建的協(xié)共同使用一個堆??臻g,這相比于任務來說,減少了RAM的使用空間。 2. 調(diào)度和優(yōu)先級 協(xié)
    發(fā)表于 12-08 08:18

    用戶在使用GPIO反跳功能時需要注意哪些限制?

    用戶在使用GPIO反跳功能時需要注意哪些限制?
    發(fā)表于 08-26 06:32

    請問用戶在使用GPIO反跳功能時需要注意哪些限制?

    用戶在使用GPIO反跳功能時需要注意哪些限制?
    發(fā)表于 08-22 07:03

    振弦式土體沉降計鉆孔埋設需要注意什么?

    、確保長期監(jiān)測穩(wěn)定性的前提。振弦式土體沉降計鉆孔埋設需要注意什么?關(guān)鍵注意事項規(guī)避施工風險工程實踐中需重點管控四類風險:鉆孔質(zhì)量控制:傾斜度偏差需≤2°,防止儀器偏斜
    的頭像 發(fā)表于 08-19 13:56 ?703次閱讀
    振弦式土體沉降計鉆孔埋設<b class='flag-5'>需要注意</b>什么?

    企業(yè)選擇SDWAN方案時,需要注意哪些?

    ##企業(yè)選擇SDWAN方案時,需要注意哪些?在數(shù)字化轉(zhuǎn)型浪潮中,企業(yè)廣域網(wǎng)正經(jīng)歷從“連通即可”向“智能、安全、云原生”的深刻變革。SD-WAN技術(shù)憑借其顛覆性的架構(gòu)理念,成為企業(yè)優(yōu)化網(wǎng)絡性能
    的頭像 發(fā)表于 08-15 10:03 ?1744次閱讀
    企業(yè)選擇SDWAN方案時,<b class='flag-5'>需要注意</b>哪些?

    IR615S橋接AP,在相同SSID 的AP間不能切換,要注意哪些設置?

    現(xiàn)場有多個AP,用相同的SSID,沒有使用AC,現(xiàn)場IR615S WiFi橋接AP WiFi時,當連接的AP關(guān)閉后,不能切換到到其他AP上,需要注意哪些設置?
    發(fā)表于 08-06 07:39

    請問工程移植都有哪些需要注意的地方?

    ST的固件庫還是挺豐富的,有時候我們直接移植工程還是挺方便的,不過總是會有各種各樣的報錯存在,在移植的時候有哪些需要注意的嗎?或者一些常見的報錯如何解決?
    發(fā)表于 07-11 06:50
    驻马店市| 拉萨市| 开江县| 海南省| 北票市| 安泽县| 桂平市| 札达县| 咸阳市| 六枝特区| 溧阳市| 岐山县| 靖江市| 廉江市| 昆山市| 利津县| 鹤峰县| 新营市| 许昌市| 蕉岭县| 洛扎县| 凤城市| 新巴尔虎右旗| 湄潭县| 芦山县| 宜昌市| 龙海市| 乌拉特中旗| 巴彦淖尔市| 西青区| 商洛市| 札达县| 揭西县| 邢台县| 孟村| 稻城县| 澜沧| 浑源县| 龙海市| 银川市| 阳城县|