【C++学习】C++11线程及线程互斥锁

系列文章目录

【C++学习】谈谈我对C++代码重构的认识
【C++学习】谈谈我对C++中delete的看法



前言

C++11在语言的层面上引入了线程,而在之前是通过Pthread库的方式引入线程库,现在通过标准库thread引入了对线程的支持,使得线程的创建和启动更加简单且更安全。引入线程的目的主要是为了实现并发,能够实现在同一进程中多个线程共享相同的地址空间,可以访问进程中的大部分数据,指针和引用可以在线程间进行传递。


一、创建和启动线程:

通过声明一个线程对象便可以创建并启动线程,在构造的参数列表中写出线程绑定的函数,在函数后用逗号来写入参数列表。

#include <iostream>
#include <thread>

using namespace std;

//定义一个简单的用于输出的函数
void func(int num) {
    
    
	cout << num << endl;
}

int main() {
    
    
	for (int i = 0; i < 5; i++) {
    
    	//每次循环创建一个线程并启动
		thread th(func, i);	//创建并启动线程,参数放在函数的后面
		th.detach();	//detach方式使线程在后台运行,稍后介绍
	}
	getchar();
	return 0;
}

输出:可以看到输出的结果并不是按照顺序递增的数列,而是乱序且中间有空格的一个数列,那是因为使用了detach()让线程在后台运行,运行的顺序是不确定的,每次运行的结果可能都不一样。

023
4

1
C:\Users\Astro\source\repos\testTime\Release\testTime.exe (进程 42100)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .

如果将detach()换成join()便会看到递增的数列:

int main() {
    
    
	for (int i = 0; i < 5; i++) {
    
    
		thread th(func, i);
		th.join();	//换成join()的方式结束线程
	}
	getchar();
	return 0;
}

输出

0
1
2
3
4

C:\Users\Astro\source\repos\testTime\Release\testTime.exe (进程 56088)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .

Note:

  • 线程参数的传递 : 默认的会将传递的参数以拷贝的方式复制到线程空间,即使参数的类型是引用
  • 如果想在调用线程的函数中更新变量,就需要使用std::ref()来将变量的引用传入线程,而不是一个拷贝。
class _tagNode
{
    
    
public:
	int a;
	int b;
};

void func(_tagNode &node)
{
    
    
	node.a = 10;
	node.b = 20;
}

void f()
{
    
    
	_tagNode node;

	thread t(func, std::ref(node));
	t.join();

	cout << node.a << endl ;
	cout << node.b << endl ;
}

二、线程的结束:

  1. detach方式,启动的线程自主在后台运行,当前的代码继续往下执行,不等待新线程结束。前面代码所使用的就是这种方式。detach相当于失去了对线程的控制,当对象析构时线程会继续在后台执行。
  2. join方式,等待启动的线程完成,才会继续往下执行。假如前面的代码使用这种方式,其输出就会0,1,2,3,因为每次都是前一个线程输出完成了才会进行下一个循环,启动下一个新线程

三、线程与互斥锁:

#include <iostream>
#include <thread>
#include <mutex>

using namespace std;

int cnt1 = 20, cnt2 = 20;

using namespace std;

int cnt = 20;
mutex m;

void t1(){
    
    
    while (cnt > 0){
    
    
        //m.lock();
        //使用lock_guard更加安全,它会自动解锁
        lock_guard<mutex> lockGuard(m);
        if (cnt > 0) {
    
    
            --cnt;
            cout << cnt << endl;
        }
        //m.unlock();
    }
}
void t2(){
    
    
    while (cnt > 0){
    
    
        m.lock();
        if (cnt > 0){
    
    
            cnt = cnt - 2;
            cout << cnt << endl;
        }
        m.unlock();
    }
}
int main()
{
    
    
    //这里可能会出现递减1 也可能会出现递减2的数列,因为资源只有一个cnt,当主函数运行时执行的顺序是不确定的,但是因为在每个线程中都设置了
    //互斥锁,所以线程之间不会去争夺cnt这个资源,而是互斥的执行
    thread th1(t1);
    thread th2(t2);

    th1.join();
    th2.join();

    return 0;
}

总结

C++中线程还有许多其他的操作,还有很多种线程之间的锁:互斥锁、条件锁、自旋锁、读写锁、递归锁等等。本文只介绍了一些基本的操作,如有不正,敬请指出!

猜你喜欢

转载自blog.csdn.net/Daibvly/article/details/120226788