在了解多线程之前我们首先需要了解并发的机制
并发:多个任务同时间段进行,一个可执行exe文件就是一个进程,并发的实现可通过执行多个exe文件或者给它开多线程。
轮询:单核cpu不能实现真正的并发,10个任务,第一个任务执行10ms,马上切换到第二个任务,看着就像多任务同时处理并发,但是是个假并发。这种方法也叫轮询
。
如果你cpu4核的,执行3线程任务,那就可以做到并发,5个任务就还是需要通过轮询,所以线程并不是越多越好。轮询会浪费CPU性能在切换上。
查询cpu核心数的代码如下:
还是国际惯例,先复制代码编译一下更容易理解。
int count = std::thread::hardware_concurrency();
printf("此电脑核心数为:%d\n" , count);
thread例子如下:
join:跟主线程汇合,等线程执行完毕再执行进程,这个就是阻塞
可以看以下代码例子:
// An highlighted block
#include<iostream>
#include<thread>
void fuction_1()
{
std::cout<<"线程开始运行" <<std::endl;
std::cout<<"Hello World" <<std::endl;
}
int main()
{
std::cout<<"进程开始" <<std::endl;
std::thread t1(fuction_1);
t1.join(); //不加jion,主线程就会继续执行,然后子线程还没结束
//程序却已经运行结束了,并且销毁了线程
//t1.detach();
std::cout<<"进程开始1" <<std::endl;
std::cout<<"进程准备结束" <<std::endl;
}
不加 t1.join,线程会继续往下走,而不管子线程
detach:分离,和主线程各走各的,但如果你先detach再join,则会报错,join方法要加个判断if(t1.joinable()),二者选一个,不然会跟主线程产生混乱冲突等
// An highlighted block
t1.detach();
if(t1.joinable())
{
t1.join();
}
detach执行后,子现场会驻留到后台运行,所以叫守护线程。
一个线程只能被deatch或join一次,可以根据实际使用需求来决定使用哪一种方法。
要注意,线程只能被move,不能被赋值,如下:move完之后,t1为空
std::thread t2=std::move(t1);
上面的是thread函数是C++11自带的一个线程函数的机制,他本源也是对pthread的一个封装,我们看原生的pthread函数如何使用:(如果输入man 2 pthread_create提示没有函数的话,需先执行下面的操作)
注意,如果你的系统更换过镜像源,则需要先把/etc/apt目录下的sources.list文件内容换回官方的源,然后执行sudo apt-get update
,之后还是可能会报错,按照提示运行这句sudo apt-get -f install
,最后才安装关于线程的man提示手册sudo apt-get install manpages-posix manpages-posix-dev
然后你输入man 2 pthread_create才能看到函数原型
头文件
#include<pthread.h>
我们先来看创建线程的函数原型pthread_create
函数声明
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
Compile and link with -pthread.
里面一共有四个参数
线程pthread函数
第一个是传出参数,当创建成功会传出新创建的线程id
第二个是只读的,描述的是线程的属性,通过调整线程属性可以调整线程分离或其他,也可以不传,写NULL即可
第三个是回调函数,返回值是void*,参数也是void*
第四个参数就是第三个参数的void*
下面那行提示就是编译的时候需手动链接线程库-pthread
下面一起写一个最简单的线程函数来加深印象。
#include<pthread.h>
#include<iostream>
#include<unistd.h>
using namespace std;
void* xiancheng(void *)
{
cout<<"i am a xiancheng"<<endl;
return NULL;
}
int main()
{
pthread_t tid;
cout<<"i am main"<<endl;
pthread_create(&tid,NULL,xiancheng,NULL);
sleep(1);
return 0;
}
加个sleep是让主线程等待子线程,当然正规的其实应该使用pthread_join函数。
我们刚才可以看到线程是可以传参的,那么这个void*类型的怎么传呢?直接把int型强转成void *吗?字节数不一样会导致数据丢失或其他问题,所以我们传指针就好
#include<pthread.h>
#include<iostream>
#include<unistd.h>
using namespace std;
void* xiancheng(void *arg)
{
int ax=(*(int*)arg);
cout<<"i am a xiancheng "<<ax<<endl;
return NULL;
}
int main()
{
pthread_t tid;
cout<<"i am main"<<endl;
int args=520;
pthread_create(&tid,NULL,xiancheng,(void*)&args);
pthread_join(tid,NULL);
return 0;
}