C++11的多线程并发编程(二)
疫情已到确诊3w+,望早日结束这疫情。
根据上一节学习的的线程概念,开始进一步学习C++11新标准的多线程编程,C++11引入了5个头文件,分别是:atomic, thread, mutex, condition_variable, future。主要包含互斥类,条件变量,同步线程和异步线程等的相关类,这一节主要记录thread头文件的相关内容。
- 线程的创建std::thread
std::thread的构造函数主要有三种:不带参数的构造函数,初始化构造函数,移动构造函数。写个代码举个栗子:
#include <iostream>
#include <thread>
#include <unistd.h>
using namespace std;
void myFunc1()
{
cout << "hello comedy" << endl;
}
void myFunc2(int i)
{
cout << "hello comedy" << i << endl;
}
int main(int argc, char *argv[])
{
int i = 99;
thread t1(myFunc1);
thread t2(myFunc2,i);
thread t3(myFunc3,i);
thread t4(move(t3));
sleep(1);
cout << "the main thread is end;" << endl;
return 0;
}
sleep(1)让主线程睡眠一秒钟,子线程有足够的时间去运行,因为进程是否执行完毕,取决于主线程是否执行结束。如主线程结束但子线程没有时间执行,则会被操作系统强制结束。
- 线程的阻塞 join()
在thread类中提供了一个函数join();表示线程的加入和回合,其作用与sleep(n)等价,用来阻塞主线程,让主线程等到子线程执行完毕。用法如例:
#include <iostream>
#include <thread>
using namespace std;
void myFunc(char *str)
{
cout << "hello " << str << endl;
}
int main(int argc, char *argv[])
{
char str[] = "comedy!";
thread t1(myFunc , str);
t1.join();
cout << "the main thread is endl;" << endl;
return 0;
}
一个良好的程序是应该是主线程等待子线程执行完毕后,自己再结束。但thread类提供了一个成员函数detach()使得,子线程和主线程自己运行自己的,且无需等待。
- 线程分离detach()
线程分离,子线程对象调用detach成员函数,使得子线程失去与主线程的关联,此时主线程结束而子线程未结束,子线程被后台C++运行库接管,分离线程即守护线程,或是缓存清理任务,或是监视文件任务。这里借鉴某个例子证明一个问题。
在Ubuntu系统指定文件目录中编写c++程序文件。
#include <iostream>
#include <thread>
using namespace std;
class myTest
{
public:
int parameter;
myTest(int i): parameter(i){}
void operator()()
{
cout << "my thread is createed" << endl;
cout << "my parameter is :" << parameter << endl;
//do something.....
cout << "my thread is end" << endl;
}
};
int main(int argc, char *argv[])
{
int x = 99;
myTest test(x);
thread mythread(test);
mythread.detach();
cout << "the main thread is end " << endl;
return 0;
}
然后通过命令执行编译链接库 g++ 8.5.cpp -o 8.5 -pthread -std=c++11
并通过命令执行 ./8.5 结果如图所示:
从图中可以看出,main线程很早就结束了,但是子线程还在执行,但是主线程的结束会这个test对象就会被销毁,那子线程的对象哪来的。通过修改案例代码:增加类的构造函数和拷贝构造函数和虚构函数。
#include <iostream>
#include <thread>
using namespace std;
class myTest
{
public:
int parameter;
myTest(int i): parameter(i)
{
cout << "myTest's createFunction is running" << endl;
}
myTest(const myTest &test): parameter(test.parameter)
{
cout << "myTest's copyFunction is running" << endl;
}
~myTest()
{
cout << "myTest's removeFunction is running" << endl;
}
void operator()()
{
cout << "my thread is createed" << endl;
cout << "my parameter is :" << parameter << endl;
//do something.....
cout << "my thread is end" << endl;
}
};
int main(int argc, char *argv[])
{
int x = 99;
myTest test(x);
thread mythread(test);
mythread.detach();
cout << "the main thread is end " << endl;
return 0;
}
运行结果如图所示:
结果显示第一个析构的对象实际上是被赋值进线程中的,执行完主线程主线程的对象被析构,当子线程执行结束时再调用析构函数。
下一节继续学习线程传参部分。