什么是单线程
在描述什么是多线程之前,先讲讲什么是单线程。
int var = 100; // 全局变量 var,初始值为 100
void func(){
var += 100;
std::cout << "now var is: " << var << std::endl; // c++ 语法,意思为输出 var 的当前值
}
int main()
{
func();
func();
}
上面这段代码中,定义了一个函数func
,并在main
中连续调用两次func
,程序执行结果如下:
now var is: 200
now var is: 300
var是一个全局变量,每次调用func
,行为都是将var
的值+100
,整个程序是顺序执行的,第一次调用func
,输出now var is: 200
,第二次调用func
输出now var is: 300
这是一个典型的单线程程序,所有代码自main函数的第一行开始,依次执行每条语句,到最后一行结束。
多线程示例
再来看一段多线程的代码
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <cstring>
int var = 100;
void* func(void * arg){
int i = *((int*)arg);
sleep(i); // 等待 i 秒
var += 100;
std::cout << i << "th pthread is created!" << " pid = " << getpid() << std::endl; // 输出线程id
std::cout << "now var is: " << var << std::endl; // 输出 var 值
return NULL;
}
int main(){
std::cout << "at first var = " << var << std::endl; // 输出 var 的起始值
const int& num = 5;
int i;
int index[num];
pthread_t tid;
for(i = 0; i < num; ++i){ // 循环创建多个线程
index[i] = i;
int ret = pthread_create(&tid, NULL, func, (void*)&(index[i])); // 创建一个线程,每个线程执行函数 func后退出
if(ret < 0){
std::cerr << "PTHREAD_CREATE " << strerror(ret) << std::endl;
exit(1); // 创建失败程序异常退出
}
}
sleep(i); // 主线程休眠 num(5) 秒
std::cout << "at last var = " << var << std::endl; // 输出 var 的最终值
return 0;
}
这段代码使用pthread_create
创建了5个线程,每个线程执行func
后退出,最后主线程退出
现在看不懂这段代码没有关系,今天主要是为了讲明白多线程和单线程的区别是什么?这段代码最终的目的就是让var
从初始值100
增加到最终值600
。要达成同等的目的,我们依旧可以使用单线程,在main
中连续调用5次func
,或者循环5次调用func
,也就是,可能写出以下的单线程代码来让var
的值从100增加到600
// 连续调用5次
int main()
{
func();
func();
func();
func();
func();
}
// 使用循环
int main()
{
for (int i = 0; i < 5; ++i) {
func();
}
}
这样看貌似单线程确实和多线程没有区别,那我们使用多线程的目的是什么?
为什么使用多线程
思考一个问题:怎样更快速的进行文件压缩?
毫无疑问,文件压缩的速度直接决定了用户的使用体验,作为一个文件压缩软件,速度是必不可少的竞争点,假如我们掌握了文件压缩的算法,其函数声明如下:
int zip_file(FILE *pfile, int offset, int length);
pfile: 文件指针
offset: 起始压缩位置
length: 压缩长度
返回值:0/1 压缩成功/失败
单线程去进行文件压缩,可能写出下面的代码
int ziped = 0; // 已经压缩的长度
int offset = 0; // 起始压缩位置,从文件开头开始
int one_zip_len = 1024 * 1024; // 每次压缩 1MB
while (ziped < pfile.size()) { // pfile.size() 文件总长度
if (zip_file(pfile, offset, one_zip_len) == 1) { // 压缩 pfile [offset, offset+one_zip_len) 之间的数据
printf("zip file %p failed, exit 1\n", pfile); // 压缩失败,退出
exit(1);
}
offset += one_zip_len; // 1MB 压缩成功,压缩下1MB
ziped += one_zip_len;
}
压缩过程如下图所示,先压缩0-1M,然后压缩1-2M,…,最后第n次调用zip_file压缩文件最后的部分
如果 zip_file
压缩1MB需要1s,压缩100M的文件就需要100s,一分半钟的时间只压缩了100MB的文件,这样的速度对于用户来说是不可接受的。
如果可以同时进行压缩数据呢?如果上图中的1-n次,可以同时执行,也就是在0-1s内,同时压缩文件的0-1M、3-4M、7-8M、11-12M,1s结束后,就压缩了4MB的数据,100MB的数据只需要25s就可以完成,效率提升了4倍。
而多线程就是创建多个线程并发执行任务,我们创建4个线程,让每个线程都去执行zip_file
,同时控制每个线程压缩不同的文件区域,就可以达到压缩效率提升4倍的效果。
这是多线程相较于单线程所带来的任务执行效率的提升,而多线程和单线程绝不仅仅这一点区别,更多内容将在后续逐步揭开,下一节将介绍线程的基本用法,如何创建、回收、设置线程执行函数等。