这是我学习B站上mkuangxiang老师发布的C++11并发与多线程课程的学习笔记,记录下来以后可以回顾一下。链接放在这里,如果有兴趣可以看一下。讲解的内容还是比较清楚。
这里我就不详细描述线程、进程这些概念了,只描述怎么创建,以及相关函数的用法,作为自己的备忘录。
首先创建多线程需要包含头文件“ thread ”;
创建一个子线程
然后创建线程入口函数(也可以是类对象、函数指针等):
函数模式:
int my_thread()
{
cout<<"新线程id为:"<<this_thread::get_id()<<endl;//输出当前线程的线程id
chrono::milliseconds time1(3000);//创建1个3000毫秒也就是3秒的时间变量
this_thread::sleep_for(time1);//线程睡眠3秒,以便观察
return 0;
}
类对象模式:
class A {//类对象模式
public:
int mythread(int i)//线程入口
{
cout << i << endl;
cout << "thread ID为:" << this_thread::get_id() << endl;
return i+1;
}
};
然后线程入口函数就创建好了,可以在里面干一些其他事
然后我们在主函数 int main中创建线程就可以了
int main()
{
cout << "主线程id为:" << this_thread::get_id() << endl;//输出主线程id以对比
thread NewThread(my_thread);//创建子线程
NewThread.join();//等待子线程执行完毕,阻塞主线程,让主线程等待子线程执行完毕,然后子线程和主线程汇合
//NewThread.detach();//使子线程与主线程分离,子线程执行完毕后由运行时库清理。
cout<<"主线程结束"<<endl;
/* //类对象模式如何使用入口函数创建子线程展示
A a;
int num=5;
//这里需要传递类引用模式方法
future<int> result=async(&A::mythread,&a,num);//需要使用#include <future>头文件
cout<<result.get()<<endl;//程序会停留在get函数处等待,用来等待线程返回结果,且只能通过get获取一次结果,(只能调用一次)
result.wait();//只是等待线程返回,本身并不返回结果
//不调用get函数,主线程在退出前依旧会等待子线程执行完毕,但依旧推荐使用get或者wait等待
*/
return 0;
}
这里的join和detach的解释为:在传统的多线程中,一般都会等待子线程执行完毕并返回,join就起到这个功能,保证子线程执行完毕,返回,主线程再继续执行下去。当然也可以不等待子线程只想完毕,那么就可以使用detach,但使用detach后,就可能出现一些问题,如果主线程中有公共资源,而恰好子线程需要需用该公共资源,而又恰好主线程比子线程执行的更快,先一步结束,那么子线程在执行中就会出现问题。
这里的future和async的解释:
async是一个函数模板,用来启动一个异步任务,返回一个future对象,可以通过get()函数获得返回结果,简单理解就是使用了async后可以通过get获取子线程返回的结果。future提过一种访问异步操作结果的机制,可以理解为future里会保存一个值
然后来看一下运行结果:
从结果可以很直白的看出,子线程与主线程的线程id是不同的,也就是我们确实创建了一个新的线程。
批量创建多个子线程
首先还是写一个线程入口函数,这里声明:多个子线程是可以共用一个线程入口函数的,例如:
void my_thread(int num)
{
cout << "新线程id为:" << this_thread::get_id() << endl;//输出当前线程的线程id
cout << "这是线程:" << num << endl;
}
主函数如下:
int main()
{
vector <thread> myThread;//声明一个线程类型的容器
for (int i = 0; i < 10; i++)
{
myThread.push_back(thread(my_thread, i));//创建新线程的同时将线程放进容器中
}
for (auto iter = myThread.begin(); iter != myThread.end(); iter++)
{
iter->join();//使用迭代器循环线程表,使其全部join等待。
}
cout << "全部子线程结束" << endl;
return 0;
}
运行结果如下:
通过结果可以看出确实创建了10个子线程,每个子线程的线程id都不同,且也运行顺序是混乱的,这是根据cpu的调度顺序来的,这里就不做研究。
这才是实际意义上的创建了多线程。但我们一直没有在子线程中做事,这是因为子线程运行如果需要取用数据的话就涉及到互斥、锁的问题,这个问题后续写,今天只讲如何创建子线程。