c 的并发编程语言,C 11 并发编程示例教程

本文介绍了C11标准如何支持并发编程,包括线程管理、同步与原子操作,以及在编写多线程程序时的关键注意事项,如线程生命周期管理和异常环境下的线程join。通过示例演示了如何正确处理线程安全问题,如避免局部变量引用和异常时的线程终止。
摘要由CSDN通过智能技术生成

C 11标准为C 编程语言的第三个官方标准,C 11包含了核心语言的新机能,并且拓展C 标准程序库,并且加入了大部分的C Technical Report 1程序库(数学上的特殊函数除外)。

C 11标准支持了并发,其中包含了线程管理,共享资源保护,线程间同步操作和底层原子操作等功能。我们先通过一个简单的示例看看C 11标准的多线程程序是什么样的。

#include     #include  // 引用用于管理线程的类的头文件        using namespace std;        // 线程的入口函数,程序将在新创建的线程中打印log    void hello()    {        cout <

程序执行结果:

a_27314

join

1. 等待线程完成

若不等待线程完成,我们就需要确保该线程访问的数据都是有效的,直到该线程完成为止。比如如下代码,线程函数持有局部变量的指针或引用,当函数退出时,线程尚未执行完成。

#include     #include             // 线程持有局部变量的指针    struct func    {        int *i;        func(int *i_) : i(i_){                }            void operator()()        {            for (unsigned j = 0; j 

要避免这种情况,需要使用std::thread实例的join()来替换my_thread.detach()的调用,这样就可以保证在函数退出前,线程已经结束。对一个给定的线程,只能调用一次join(),一旦调用了join(),此std::thread对象不再是可连接的,如果调用其的joinable()将返回false。

2. 在异常环境下的等待

我们需要在线程对象被销毁前调用join或detach方法,如果要detach,通常在线程启动后就立即调用detach方法。如果打算等待该线程,就需要仔细的选择在哪个位置调用join。如果在线程开始之后,调用join之前发生了异常,则可能跳过对join的调用。

为了避免应用程序在引发异常的时候被终止,你需要异常时也调用join。

void do_something_in_current_thread()    {        throw("error");    }        // 不等待线程执行完成就退出    void oops()    {        int some_local_state = 0;        func my_func(&some_local_state);        std::thread my_thread(my_func);            try        {            do_something_in_current_thread();        }        catch (const char *err_msg)        {            my_thread.join();            throw;        }                my_thread.join();    }

try/catch块可以确保无论函数时正常退出还是异常退出,都调用了线程的join方法,但是try/catch块看起来很??拢?踩菀椎贾伦饔糜诨炻遥??虻サ陌旆ㄊ鞘褂?AII-Resource Acquisition Is Initialization并提供一个类,在析构函数中调用join():

class thread_guard    {        std::thread& t;    public:        explicit thread_guard(std::thread& t_) :            t(t_)        {        }            // 析构函数中检查线程是否还未被join,若没有,则调用        ~thread_guard()        {            if (t.joinable())            {                t.join();            }        }            // 将拷贝后赋值运算符标记为=delete以避免编译器自动生成,复制或赋值这样一个对象可能很危险,因为它可能比它要结合的线程的作用域存在得更久。        thread_guard(thread_guard const&) = delete;        thread_guard& operator=(thread_guard const&) = delete;    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值