c++多线程入门(1)

资料整合来源书籍: c++并发编程实战

一: 运行线程

        方法1: 传入函数

        方法2:用函数对象(重载了圆括号运算符)

        方法3:用lambda表达式

//输出语句若用cout<< *** <<endl可能会乱序
void func()
{
    cout<< "int func()\n";
}
class A
{
public:
    void operator()()const
    {
        cout<< "int class A\n" ;
    }
};
int main()
{
    auto l=[]{cout<< "in lambda\n";};
    A a;
    
    //定义函数调用
    thread t1(func);
    
    //定义类来调用
    //1.通过实例对象
    thread t2_0(a);
    //2,3 
    //注意不能  thread t(A()), 这样会解释成函数声明,函数名是t,接收一个参数,返回thread
    thread t2_1((A()));
    thread t2_2{A()};
    
    //定义lambda调用
    thread t3(l);
    
    t1.join();t2_0.join();t2_1.join();t2_2.join();
}

运行结果

        方法4:成员函数指针+对象双参数传递的方式

class A
{
public:
    void func()
    {
        cout<< "in A::func()" <<endl;
    }
};
int main()
{
    A a;
    //第一个参数为成员函数指针, 第二个参数为执行对象, 即线程执行a.func()函数
    thread t1(&A::func,&a);
    t1.join();
}

二: 线程等待

int main()
{
    int i = 1;
    A a(i);
    thread t1(a);
 
    t1.join();
    //thread 在销毁前必须调用二者之一
    //t.join()  主线程阻塞直至子线程结束
    //或t.detach()  交给运行库管理,主线程继续往下走
}

  若调用detach()时, 可能出现的问题:

         子线程引用主线程的数据, 而主线程结束后销毁了数据, 子线程还在运行, 就会造成悬空访问

示例:

class A
{
    int &i;
public:
    A(int &i_) : i(i_)
    {}
    void operator()() const
    {
        int j;
        for (j = 0; j < 100000; j++)
        {
            printf("i:%d\n", i);
            //子线程的i是引用, 主线程i销毁后, 会造成悬空引用
        }
    }
};
int main()
{
    int i = 1;
    A a(i);
    thread t1(a);
    t1.detach();
    //此时主线程结束, 销毁i, 子线程访问i出错    
}

-----------------------------

在线程销毁前必须调用join或detach, 否则出错(下面只示例join), 

于是在出现异常的情况下须保证所有出口都要调用join(),  代码显得冗余...

void f()
{
    int i = 1;
    A a(i);
    thread t1(a);
    try
    {
        //...
    }
    catch (...)
    {
        t1.join();
        throw ;
    }
    t1.join()
}

理想方案: 可以利用析构函数实现线程销毁前自动调用join()

class thread_guard
{
    thread &t;
public:
    explicit thread_guard(thread &t_) : t(t_)
    {}
    
    ~thread_guard()
    {
        if (t.joinable())
        {
            t.join();
        }
    }
    thread_guard(thread_guard const &) = delete;
    thread_guard &operator=(thread_guard const &) = delete;
};
void f()
{
    thread t1(func);
    thread_guard guard(t1);
    //即使不主动调用t1.join, 也会在f结束时, 在guard的析构函数里调用
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值