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;
}