Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >packaged_task挂在操作符()上

packaged_task挂在操作符()上
EN

Stack Overflow用户
提问于 2015-01-08 14:48:57
回答 2查看 759关注 0票数 12

在Ubuntu上用gcc 4.7.2编译,用-std=c++11 -O0 -pthread编译,我在代码中造成了一个死锁,看起来不应该遇到这个问题。我有一个线程,它只是获取一个锁,然后运行在一个vector<function<void()>>中,调用所有的东西。同时,主线程将std::packaged_task<int()>逐个推到上面,并在任务的future返回时阻塞。任务本身是微不足道的(打印和返回)。

这是完整的代码。运行该应用程序有时会成功,但几次尝试就会挂起:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>
#include <future>
#include <thread>
#include <vector>
#include <functional>

std::unique_lock<std::mutex> lock() {
    static std::mutex mtx;
    return std::unique_lock<std::mutex>{mtx};
}

int main(int argc, char** argv)
{
    std::vector<std::function<void()>> messages;
    std::atomic<bool> running{true};

    std::thread thread = std::thread([&]{
        while (running) {
            auto lk = lock();
            std::cout << "[T] locked with " << messages.size() << " messages." << std::endl;
            for (auto& fn: messages) {
                fn();
            }   
            messages.clear();
        }   
    }); 

    for (int i = 0; i < 1000000; ++i) {
        std::packaged_task<int()> task([=]{
            std::cout << "[T] returning " << i << std::endl;
            return i;
        }); 

        {   
            auto lk = lock();
            messages.emplace_back(std::ref(task));
        }   

        task.get_future().get();
    }   

    running = false;
    thread.join();
}

样本输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[T] returning 127189
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 1 messages.
[T] returning 127190
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 1 messages.
[T] returning 127191
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 1 messages.
... hangs forever ...

到底怎么回事?为什么进入packaged_task::operator()的电话挂起?僵局在哪里?这是gcc的窃听器吗?

在死锁时更新,这两个线程位于:

线程1(第39行是task.get_future().get()行):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#0  pthread_cond_wait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162
#1  0x00007feb01fe800c in __gthread_cond_wait (this=Unhandled dwarf expression opcode 0xf3
)
    at [snip]/libstdc++-v3/include/x86_64-unknown-linux-gnu/bits/gthr-default.h:879
#2  std::condition_variable::wait (this=Unhandled dwarf expression opcode 0xf3
) at [snip]/gcc-4.7.2/libstdc++-v3/src/c++11/condition_variable.cc:52
#3  0x0000000000404aff in void std::condition_variable::wait<std::__future_base::_State_base::wait()::{lambda()#1}>(std::unique_lock<std::mutex>&, std::__future_base::_State_base::wait()::{lambda()#1}) (this=0x6111e0, __lock=..., __p=...)
    at [snip]gcc-4.7.2/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/condition_variable:93
#4  0x0000000000404442 in std::__future_base::_State_base::wait (this=0x6111a8)
    at [snip]gcc-4.7.2/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/future:331
#5  0x00000000004060fb in std::__basic_future<int>::_M_get_result (this=0x7fffc451daa0)
    at [snip]gcc-4.7.2/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/future:601
#6  0x0000000000405488 in std::future<int>::get (this=0x7fffc451daa0)
    at [snip]gcc-4.7.2/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/future:680
#7  0x00000000004024dc in main (argc=1, argv=0x7fffc451dbb8) at test.cxx:39

线程2(第22行是fn()行):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#0  pthread_once () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S:95
#1  0x00000000004020f6 in __gthread_once (__once=0x611214, __func=0x401e68 <__once_proxy@plt>)
    at [snip]/gcc-4.7.2/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/x86_64-unknown-linux-gnu/bits/gthr-default.h:718
#2  0x0000000000404db1 in void std::call_once<void (std::__future_base::_State_base::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()()>&, bool&), std::__future_base::_State_base* const, std::reference_wrapper<std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()()> >, std::reference_wrapper<bool> >(std::once_flag&, void (std::__future_base::_State_base::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()()>&, bool&), std::__future_base::_State_base* const&&, std::reference_wrapper<std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()()> >&&, std::reference_wrapper<bool>&&) (__once=..., __f=@0x7feb014fdc10)
    at [snip]/gcc-4.7.2/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/mutex:819
#3  0x0000000000404517 in std::__future_base::_State_base::_M_set_result(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()()>, bool) (this=0x6111a8, __res=..., __ignore_failure=false)
    at [snip]/gcc-4.7.2/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/future:362
#4  0x0000000000407af0 in std::__future_base::_Task_state<int ()()>::_M_run() (this=0x6111a8)
    at [snip]/gcc-4.7.2/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/future:1271
#5  0x00000000004076cc in std::packaged_task<int ()()>::operator()() (this=0x7fffc451da30)
    at [snip]/gcc-4.7.2/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/future:1379
#6  0x000000000040745a in std::_Function_handler<void ()(), std::reference_wrapper<std::packaged_task<int ()()> > >::_M_invoke(std::_Any_data const&) (
    __functor=...) at [snip]/gcc-4.7.2/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/functional:1956
#7  0x00000000004051f2 in std::function<void ()()>::operator()() const (this=0x611290)
    at [snip]/gcc-4.7.2/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/functional:2311
#8  0x000000000040232f in operator() (__closure=0x611040) at test.cxx:22
#9  0x0000000000403d8e in _M_invoke<> (this=0x611040)
    at [snip]/gcc-4.7.2/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/functional:1598
#10 0x0000000000403cdb in operator() (this=0x611040)
    at [snip]/gcc-4.7.2/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/functional:1586
#11 0x0000000000403c74 in _M_run (this=0x611028) at [snip]/gcc-4.7.2/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/thread:115
#12 0x00007feb01feae10 in execute_native_thread_routine (__p=Unhandled dwarf expression opcode 0xf3
) at [snip]/gcc-4.7.2/libstdc++-v3/src/c++11/thread.cc:73
#13 0x00007feb018879ca in start_thread (arg=<value optimized out>) at pthread_create.c:300
#14 0x00007feb015e569d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:112
#15 0x0000000000000000 in ?? ()
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-01-08 17:50:32

问题似乎是,您可能在工作线程中的packaged_task返回之前销毁operator()。这很可能是不明确的行为。如果我在等待未来返回结果后,在循环中重新创建互斥体,这个程序对我来说很好。这将序列化operator()和packaged_task的析构函数。

票数 5
EN

Stack Overflow用户

发布于 2015-01-08 15:49:05

我无法解释为什么您的代码被破坏了,但我确实找到了一种修复它的方法(存储任务,而不是从任务构建的std::functions ):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>
#include <future>
#include <thread>
#include <vector>
#include <functional>
#include <unistd.h>

int main(int argc, char** argv)
{
    // Let's face it - your lock() function was kinda weird.
    std::mutex mtx;

    // I've changed this to a vector of tasks, from a vector
    // of functions. Seems to have done the job. Not sure exactly
    // why but this seems to be the proper way to go.
    std::vector<std::packaged_task<int()>> messages;

    std::atomic<bool> running{true};

    std::thread thread([&]{
        while (running) {
            std::unique_lock<std::mutex> l{mtx};
            std::cout << "[T] locked with " << messages.size() << " messages." << std::endl;
            for (auto& fn: messages) {
                fn();
            }
            messages.clear();
        }
    });

    for (int i = 0; i < 1000000; ++i) {
        std::packaged_task<int()> task([i]{
            std::cout << "[T] returning " << i << std::endl;
            return i;
        });

        // Without grabbing this now, if the thread executed fn()
        // before I do f.get() below, it complained about having
        // no shared state.
        std::future<int> f = task.get_future();

        {
            std::unique_lock<std::mutex> l{mtx};
            messages.emplace_back(std::move(task));
        }

        f.get();
    }

    running = false;
    thread.join();
}

至少,如果这段代码也存在死锁,那么对我来说还没有。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27850962

复制
相关文章
面试挂在了 LRU 缓存算法设计上
好吧,有人可能觉得我标题党了,但我想告诉你们的是,前阵子面试确实挂在了 RLU 缓存算法的设计上了。
帅地
2019/06/06
1.4K1
面试挂在了 LRU 缓存算法设计上
Centos 挂在iSCSI磁盘
然后就可以像操作本地磁盘一样来操作 iscsi 磁盘 了。由于iscsi使用了多链路,所以我们multipath做链路聚合
jwangkun
2022/11/14
2.4K0
c语言操作符(上)
其中重点提一下‘/’(除)和‘%’(取余)操作符 ,其它3个太简单就不介绍了,相信大家都懂.
初阶牛
2022/12/29
6030
c语言操作符(上)
Linux 挂在硬盘步骤
Disk /dev/xvdb doesn't contain a valid partition table
海涛
2019/09/02
20.6K0
5年Java开发经验,面试挂在MySQL InnoDB上!大厂究竟多看重MySQL?
前一段时间好兄弟找工作,面试 Java 资深研发工程师岗位,接到了不少大厂的面试邀请,有顺利接到 offer 的,也有半道儿面试被卡掉的。但最想去的企业却因为 MySQL表存储引擎 InnoDB ,与 offer 失之交臂。
烂猪皮
2020/09/01
6560
5年Java开发经验,面试挂在MySQL InnoDB上!大厂究竟多看重MySQL?
java基础之基本操作符的使用(上)
  几乎所有运算符都只能操作八大基本类型。唯一的例外是下面三个,它们能操作所有对象。 “=”、“==”、“!=”   除此以外,String 类也支持“+”和“+=”。
jiankang666
2022/05/13
2820
java基础之基本操作符的使用(上)
【Kotlin 协程】Flow 操作符 ② ( 末端操作符 | collect 操作符 | reduce 操作符 | single 操作符 | first 操作符 | toList 操作符 )
末端操作符 指的是 在 Flow 流最末端 调用 挂起函数 收集元素 的操作符 , 最常见的 末端操作符 就是 collect 操作符 ;
韩曙亮
2023/03/30
1K0
【Kotlin 协程】Flow 操作符 ② ( 末端操作符 | collect 操作符 | reduce 操作符 | single 操作符 | first 操作符 | toList 操作符 )
C#语言入门详解-10操作符详解(上)
http://mpvideo.qpic.cn/0bf2saaaiaaaoyaalqk6hjpvbegdasiaabaa.f10002.mp4?dis_k=94fb079b83170635c299ead
宿春磊Charles
2022/03/29
1330
JavaScript操作符(关系操作符、相等操作符和条件操作符)
关系操作符用于对两个值进行比较,返回一个布尔值。关系操作符包括大于(>),小于(<),大于等于(>=),小于等于(<=)。当关系操作符用于非数值时,也要先进行数值的转换。如 var result=5>3; 1.尝试将两个操作符转换为数字; 2.如果两个操作符均为字符串,则进行字符串的比较 3.如果任一表达式为NaN,则返回false; 4.-0等于+0; 5.负无穷小于包含自身在内的任何数 6.正无穷大于包含自身在内的任何数 相等操作符,用于确定两个变量是否相等。字符串、数值、布尔值的相等比较是简单的,对象
水击三千
2018/02/27
1K0
JavaScript操作符(布尔操作符、乘性操作符和加性操作符)
布尔操作符 布尔操作符用来测试两个值的关系,布尔操作符有三个,逻辑非(!)、逻辑与(&&),逻辑或(||)。 逻辑非由一个叹号(!)组成,可以应用于JavaScript任何值。逻辑非首先将它的操作数转换为一个布尔值,然后再对布尔值求反。 console.log(!NaN);//true console.log(!123);//false console.log(!"");//true console.log("");//false console.log(!{});//false 逻辑与由两个和号表示(&&
水击三千
2018/02/27
6370
【Kotlin 协程】Flow 操作符 ① ( 过渡操作符 | map 操作符 | transform 操作符 | 限长操作符 | take 操作符 )
代码示例 : 将 Flow 中发射的 Int 元素 转为 字符串 ; 通过 map 操作符 , 将 Int 类型的元素 转为 字符串类型 元素 ;
韩曙亮
2023/03/30
8520
【Kotlin 协程】Flow 操作符 ① ( 过渡操作符 | map 操作符 | transform 操作符 | 限长操作符 | take 操作符 )
UNIX(多线程):12---async、future、packaged_task、promise
【线程1中返回值,线程2调用(promise + future 起连接作用),实现两个线程之间数据传递】
用户3479834
2021/02/03
4520
UNIX(多线程):12---async、future、packaged_task、promise
JavaScript操作符(一元操作符、位操作符)
JavaScript操作符包括算术操作符、位操作符、关系操作符和相等操作符。只能操作一个值的操作符叫做一元操作符。 递增和递减操作符 递增和递减操作符有两个版本:前置型和后置型。前置型操作符位于要操作的变量之前,后置型操作符位于要操作的变量之后。 需要将一个变量的值在使用前就进行加减操作,一般使用前置操作符。 var age=18; console.log(++age);//前置型操作符是先计算,返回计算后的值。输出为19 console.log(age);//输出19; console.log(--age
水击三千
2018/02/27
8530
Rxjava 2.x 源码系列 - 变换操作符 Map(上)
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gdutxiaoxu/article/details/80684901
程序员徐公
2018/09/17
4130
Rxjava 2.x 源码系列  -  变换操作符 Map(上)
JavaScript操作符之算数操作符
这里不多说,如果两个操作数都是数字,那就是相加,如果有一方是字符串,那就是两个操作数拼接。遵循如下规则
青年码农
2021/03/23
4750
JavaScript操作符之逻辑操作符
这个操作符始终返回布尔值,无论什么数据类型,逻辑非操作符始终先将操作数据转换为布尔值,之后在进行取反。
青年码农
2021/03/23
6650
操作符
**+,-,,/,% 主要是注意 % 运算符 该运算符只能用于整数,得到的是余数。其他的都比较简单
code-child
2023/05/30
2040
操作符
JavaScript操作符之相等操作符
判断两个值是否相等,我们一般是a==b来判断,其他的编程语言也是一样,但是在JavaScript中,还有===这种操作。
青年码农
2021/03/23
3580
JavaScript操作符之关系操作符
上面这种是针对数值的判断,但是现实中可能不这么美好,有时需要不同类型的也需要判断。
青年码农
2021/03/23
4290
操作符
算术运算符:+ - * / % ++ -- 一元运算符:++ -- ! 逻辑运算符:&||! 比较运算符 == === != > < >= <= 赋值运算= += -= /= %= 运算符的优先级有以下几种: ()优先级最高 一元运算符:++、 -- 算数运算符:先* / % 再+ - 关系运算符: >、 < 、>=、 <= 相等运算符:== 、!=、===、!= 逻辑运算符:先&& 后||
河湾欢儿
2018/09/06
3040

相似问题

为什么BinaryReader挂在ReadString()上,而不挂在Read()上?

13

HikariCP挂在getConnection上

21

挂在jQuery码上

20

查询挂在begin上

11

NSTask挂在readDataToEndOfFile上

25
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文