并发、线程的基本概念&线程启动结束
并发、进程、可执行程序、进程、线程的基本概念
1.并发
并发当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间段分配给各个线程执行,在一个时间段的线程代码运行时,其它线程处于挂起状。每次切换需要额外的开销(保存运行状态、还原现场)占用程序运行时间。线程的数量过多效率反而下降。
2.并行
当系统有一个以上CPU时,则线程的操作有可能非并发。当一个CPU执行一个线程时,另一个CPU可以执行另一个线程,两个线程互不抢占CPU资源,可以同时进行。
3.可执行程序
一个文件,windows下以.com或.exe为后缀,liunx,ls -la,rwxrwxrwx(x执行权限)
4.进程
计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。(可执行程序运行起来)
5.线程
又叫轻量进程,是程序执行流的最小单元。每一个进程有一个主线程,可以有多个线程。一个进程内的线程共享内存(全局变量、指针、引用可在线程间传递,开销小于多进程,但是会造成数据一致性的问题)。
线程启动结束
主线程从main()函数开始,自己创建的线程也需要从一个函数开始执行,这个函数执行完成,则线程消亡。
如果主线程结束,进程结束,一般情况下该进程的所有线程结束。
thread:标准库里的一个类
join() (汇合)
join:阻塞主线,让主线程等待子线程执行完毕
用函数
#include<iostream>
#include<thread>
using namespace std;
void print()
{
cout<<"子线程开始"<<endl;
cout<<"子线程结束"<<endl;
}
int main()
{
thread myThread(print); //创建线程(入口为print())
myThread.join(); //阻塞主线程 等待子线程执行完成
cout<<"主线程结束"<<endl;
return 0;
}
用类对象
#include<iostream>
#include<thread>
using namespace std;
class TA
{
public:
void operator()() //重载(),不能带参数
{
cout<<"子线程开始"<<endl;
cout<<"子线程结束"<<endl;
}
};
int main()
{
TA ta;
thread myThread(ta); //传入可调用对象
myThread.join(); //阻塞主线程 等待子线程执行完成
cout<<"主线程结束"<<endl;
return 0;
}
用lambda表达式
#include<iostream>
#include<thread>
using namespace std;
int main()
{
auto my = []{
cout<<"子线程"<<endl;
};
thread myThread(my); //传入可调用对象
myThread.join();
return 0;
}
如果去掉myThread.join();可能会出现主线程执行完后子线程未执行完成。
detach() (分离)
detach:主线程和子线程分离,主线程可以先执行完成,不用和子线程汇合。
detach后主线程关联和thread对象会与主线程失去关联,子线程会到后台运行。
以下程序有一个坑点!!!
在用detach()时,当主线程执行完成后,类中值引用的主线程局部对象val将会被回收,但是子线程依然要打印val的值,此时程序时错误的!(引用,指针局部对象)
创建子线程中的局部的类对象是被复制到线程中去的,所以没有问题。
#include<iostream>
#include<thread>
using namespace std;
class TA
{
public:
int &val;
TA(int &val):val(val){}
void operator()() //重载(),不能带参数
{
cout<<val<<endl;
}
};
int main()
{
int val=100;
TA ta(val);
thread myThread(ta); //传入可调用对象
myThread.detach();
return 0;
}
joinable()
判断是否能join()或detach()