笔记:C++多线程基础

本文深入探讨了并发、进程和线程的概念,重点介绍了C++中使用``库创建线程的方法,包括`join()`和`detach()`函数的使用。此外,还展示了如何通过类对象、lambda表达式、带参函数等方式创建线程,并讨论了线程间的参数传递和资源管理。
摘要由CSDN通过智能技术生成

学习于此视频

1.并发、进程、线程概念:

并发:两个或多个独立的活动同时进行
并发假象:单核CPU在极短的时间进行任务切换(上下文切换方式)

进程:计算机中的程序关于某个数据集合上的一次运行活动(exe运行状态)

线程:线程是一个运行代码的通道/路径。
每一个进程都有一个主线程并且只有一个主线程,vs运行实际上是主线程调用main()函数。

并发的实现:
1.多进程实现并发:主要解决的问题是进程间通讯的问题
一台PC上实现并发:管道、通道、消息队列、内存共享。
不同电脑:通过网络通讯(socket)

2.单个进程多线程并发:一个主线程,多个子线程实现并发
一个进程中的所有线程共享的内存空间 例如:指针引用、全局变量(资源竞争问题)

2.创建线程的多种方式

C++中创建线程的方式

1.包含头文件 #include< thread >
2.创建线程:调用thread类创建对象
note:若创建一个线程,不做处理会调用abort()函数终止程序
3.join函数汇合线程,阻塞主线程,等待子线程执行结束回到主线程。一个线程只能join一次

#include <iostream>
#include <thread>
#include <Windows.h>

using namespace std;

void print1()
{
	Sleep(5000);
	cout << "子线程1" << endl;
}
void print2()
{
	Sleep(5000);
	cout << "子线程2" << endl;
}

int main()
{
	thread test1(print1);
	thread test2(print2);
	test1.join();
	test2.join();
	cout << "主线程" << endl;

}

在这里插入图片描述
由于各个子线程都是并发运行的,所以只Sleep了5秒,并且很明显能看出来 <<endl 没有换行。

4.detch()函数,分离、打破依赖关系。可以分离子线程和主线程,主线程不会阻塞,子、主线程同时运行,但是主线程运行结束,进程结束,子线程会驻留后台。


void print1()
{
	
	cout << "子线程1" << endl;
}

int main()
{
	thread test1(print1);
	test1.detach();
	Sleep(5000);
	cout << "主线程" << endl;

}

在这里插入图片描述
子线程会先输出,休眠5s后主线程再输出。

void print1()
{
	cout << "子线程1" << endl;
	Sleep(5000);
	cout << "子线程1重复" << endl;
}

int main()
{
	thread test1(print1);
	test1.detach();
	Sleep(3000);
	cout << "主线程" << endl;

}

主线程结束,子线程会驻留后台。
在这里插入图片描述
线程detch()以后不能再join()了

5.joinable():判断当前线程是否可以做join()\detch(),可以返回true,不可以返回false。

int main()
{
	thread test1(print1);
	test1.detach();
	

	cout << "主线程" << endl;
	if (!test1.joinable())
	{
		cout << "线程已被处理" << endl;
	}
	return 0;
}

在这里插入图片描述

其他创建线程方式

1.类和对象作为参数创建线程
2.lambda表达式作为参数创建线程
3.带参函数作为参数创建线程
4.带智能指针作为参数创建线程
5.类的成员函数作为参数创建线程
6.无参函数作为参数创建

1.类和对象作为参数创建线程: 通过重载()运算符来实现线程的创建

class A
{
public:
    void operator()()
    {
        Sleep(2000);
        cout << "子线程" << endl;
    }
};

int main()
{
    thread test1((A()));//创建无名对象的方式
    A a;
    thread test2(a);//创建有名对象的方式;
    test1.join();
    test2.join();
    
}
class A
{
public:
    void operator()()
    {
        cout << "a = " << a << endl;
    }
    A(int a) :a(a) {};
private:
    int a;
};

int main()
{
    A a(10);
    thread test(a);
    test.join();
    return 0;
}

2.lambda表达式作为参数创建线程: 通过lambda表达式返回的函数指针创建线程。

[ capture ] ( params ) opt -> ret { body; };//lambda表达式
thread test([] {cout << "子线程" << endl; });
test.join();

3.以带参的方式函数作为参数创建线程:

传值参数的线程创建只需要,将所需要的参数添加到函数名后即可

void print(int num)
{cout << num <<endl;}

int main()
{
   int num = 0;
   thread test(print,num);
   test.join();
   return 0;
}

引用带参的方式需要利用ref函数包装参数值传入子线程

void print(int& num)
{
   num++;
   cout << num <<endl;
}

int main()
{
   int num = 0;
   thread test(print,ref(num));
   test.join();
   cout << num <<endl;
   return 0;
}

在这里插入图片描述

4.智能指针为参数创建线程: 利用move函数将智能指针移动到子线程中,但是主线程中会消失。

void print(unique_ptr<int> p)
{
   cout << p.get() <<endl;
}
int main()
{
     unique_ptr<int> p(new int(1000));
     cout << p.get() <<endl;
     thread test(print,move(p));
     test.join();
     cout << p.get() <<endl;
     return 0;
}

在这里插入图片描述
5.类的成员函数作为参数创建线程: 传3个参数类中成员函数的地址,对象,成员函数的参数

class A
{
    public:
        void print(int& num)
        {
             cout << num << endl;
             num++;
        }
};

int main()
{
     A a;
     int num = 99;
     thread test(&A::print,a,ref(num));
     test.join();
     cout << num << endl;
     return 0;
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值