【C++】线程库常用接口

1.创建线程,等待线程,获取线程id

2.全局变量,局部变量,互斥锁

要让不同的线程访问同一个变量和同一把锁,有两种方法:

2.1方法一

定义全局的变量和全局的锁,这样自然就能访问到。

但全局变量在多个源文件重命名的话,在链接时容易出现链接错误。

2.2方法二

在主线程处定义局部的变量和局部的锁,不过要传引用。

特别注意:在传参的时候要用ref修饰变量和锁,因为C++的线程库只是对底层系统调用的封装。

Linux系统中,系统调用pthread_create要求传进来函数参数要是void*,返回值是void*,下面一个参数是作为该函数的参数,类型是void*。所以C++的线程库要对100,x,mtx封装成结构体,后面还要把这个结构体的每一个成员解析出来交给线程函数去调用,这其中有很多步骤只是值拷贝,而不是引用传参。

所以用ref修饰一下就是强制要求在上述步骤中的传参全部用引用的方式传参,这样多个线程函数才能访问到同一个局部变量。

当然也可以直接传指针,这样底层对指针进行值拷贝也没事。

3.lambda表达式构造线程

方式一:

方式二:

3.1构造多线程

4.解决死锁问题:lock_guard

试想一下,如果有一个线程在lock和unlock之间抛异常了的话,那就不会解锁,就出现了死锁问题。

为了解决死锁问题,C++11封装了一个LockGuard的类。它的构造函数就是把传进来的锁保存起来,然后上锁。析构函数就是解锁。这样一来,就算线程在访问临界区抛异常了,线程结束前也会调用析构函数解锁。这里注意:锁不支持拷贝构造,所以LockGuard的成员变量要用mutex&。

那么如何让新封装出来的锁只锁住临界区呢:

简单定义一个局部域就可以了!花括号是可以定义局部域的,出了一个局部域之后,会自动调用析构函数。当然这个是我们自己封装出来的,调用库中的接口如下:

5.atomic

头文件是<atomic>。

atomic<int> x=0;表示下面对x的一些加减等简单的操作是原子的。

可用于一些小的修改,小的操作,保证线程安全。在部分情况下可代替锁。

这样做的效率和锁的效率差不多。

这样可以直接cout打印,但是要用printf的话,需要x.load().来打印。

6.条件变量

直播样例:

这个程序就是构建出两个线程,一个线程打印偶数一个线程打印奇数,且必须先打印0后打印1,这样来回交替。

其中条件变量是配合flag使用的,一旦调用c.wait()(非原子,需要调用互斥锁),该线程必定会阻塞(且在阻塞前会解锁),等待其他线程唤醒。c.notify()是随机唤醒一个线程,如果没有线程阻塞,那么啥也不干。

unique_lock和lock_guard功能类似。

课件样例:

这是条件变量的第二种等待方式,与第一种类似。第一个参数是锁,在阻塞时会解锁。第二个参数是一个仿函数,它的返回值为真就不阻塞,返回值为假就阻塞。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

崽崽..

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值