在C++学习过程中,要想“更上一层楼”的话,多线程编程是必不可少的一步,前面的文章多半是基础方面的内容,这节的话稍微有点拔高。所以说,我们在看这篇文章的时候,大家需要更多的思考是为什么这么做?这样做的好处是什么?以及多线程编程都可以应用在哪里?话不多说,跟着我一起认真探讨这块内容。
1、多线程
传统的C++(C++11标准之前)中并没有引入线程这个概念,在C++11出来之前,如果我们想要在C++中实现多线程,需要借助操作系统平台提供的API,比如Linux的,或者windows下的 。
C++11提供了语言层面上的多线程,包含在头文件中。它解决了跨平台的问题,提供了管理线程、保护共享数据、线程间同步操作、原子操作等类。C++11 新标准中引入了5个头文件来支持多线程编程,如下图所示:
1.1、多进程与多线程
-
多进程并发
使用多进程并发是将一个应用程序划分为多个独立的进程(每个进程只有一个线程),这些独立的进程间可以互相通信,共同完成任务。由于操作系统对进程提供了大量的保护机制,以避免一个进程修改了另一个进程的数据,使用多进程比使用多线程更容易写出相对安全的代码。但是这也造就了多进程并发的两个缺点:
-
在进程间的通信,无论是使用信号、套接字,还是文件、管道等方式,其使用要么比较复杂,要么就是速度较慢或者两者兼而有之。
-
运行多个线程的开销很大,操作系统要分配很多的资源来对这些进程进行管理。
当多个进程并发完成同一个任务时,不可避免的是:操作同一个数据和进程间的相互通信,上述的两个缺点也就决定了多进程的并发并不是一个好的选择。所以就引入了多线程的并发。
-
多线程并发
多线程并发指的是在同一个进程中执行多个线程。
优点:
有操作系统相关知识的应该知道,线程是轻量级的进程,每个线程可以独立的运行不同的指令序列,但是线程不独立的拥有资源,依赖于创建它的进程而存在。也就是说,同一进程中的多个线程共享相同的地址空间,可以访问进程中的大部分数据,指针和引用可以在线程间进行传递。这样,同一进程内的多个线程能够很方便的进行数据共享以及通信,也就比进程更适用于并发操作。
缺点:
由于缺少操作系统提供的保护机制,在多线程共享数据及通信时,就需要程序员做更多的工作以保证对共享数据段的操作是以预想的操作顺序进行的,并且要极力的避免死锁(deadlock)。
1.2、多线程理解
-
单CPU内核的多个线程。
一个时间片运行一个线程的代码,并不是真正意义的并行计算。
-
多个cpu或者多个内核
可以做到真正的并行计算。
1.3、创建线程
创建线程很简单,只需要把函数添加到线程当中即可。
-
形式1:
std::thread myThread ( thread_fun);
//函数形式为void thread_fun()
myThread.join();
//同一个函数可以代码复用,创建多个线程
-
形式2:
std::thread myThread ( thread_fun(100));
myThread.join();
//函数形式为void thread_fun(int x)
//同一个函数可以代码复用,创建多个线程
-
形式3:
std::thread (thread_fun,1).detach();
//直接创建线程,没有名字
//函数形式为void thread_fun(int x)
-
For Example
使用g++编译下列代码的方式:
g++ test.cc -o test -l pthread
#include
#include
using namespace std;
void thread_1()
{
cout<<"子线程1"<<endl;
}
void thread_2(int x)
{
cout<<"x:"<<x<<endl</x<<;
cout<<"子线程2"<<endl;
}
int main()
{
thread first ( thread_1); // 开启线程,调用:thread_1()
thread second (thread_2,100); // 开启线程,调用:thread_2(100)
//thread third(thread_2,3);//开启第3个线程,共享thread_2函数。
std::cout << "主线程\n";
first.join(); //必须说明添加线程的方式
second.join();
std::cout << "子线程结束.\n";//必须join完成
return 0;
1.4、join与detach方式
当线程启动后,一定要在和线程相关联的thread销毁前,确定以何种方式等待线程执行结束。比如上例中的join。
-
detach方式,启动的线程自主在后台运行,当前的代码继续往下执行,不等待新线程结束。
-
join方式,等待启动的线程完成,才会继续往下执行。
可以使用joinable判断是join模式还是detach模式。
if (myThread.joinable()) foo.join();
(1)join举例
下面的代码,join后面的代码不会被执行,除非子线程结束。
#include
#include
using namespace std;
void thread_1()
{
while(1)
{
//cout<<"子线程1111"<<endl;< span=""></endl;<>
}
}
void thread_2(int x)
{
while(1)
{
//cout<<"子线程2222"<<endl;< span=""></endl;<>
}
}
int main()
{
thread first ( thread_1); // 开启线程,调用:thread_1()
thread second (thread_2,100); // 开启线程,调用:thread_2(100)
first.join(); // pauses until first finishes 这个操作完了之后才能destroyed
second.join(); // pauses until second finishes//join完了之后,才能往下执行。
while(1)
{
std::cout << "主线程\n";
}
return 0;
}
(2)detach举例
下列代码中,主线程不会等待子线程结束。如果主线程运行结束,程序则结束。
#include
#include