一、线程
1.1 线程的概念
线程是轻量级的进程。
进程是分配资源的最小单位,线程是调度的最小单位。
线程不会单独分配内存空间,线程共用进程的资源。
线程之间通信比较方便,但是不安全。
多线程没有多进程安全。
多线程效率比较高。线程创建比较快,公用进程的资源。线程上下文的切换比较迅速,因为线程占用的内存资源少。
多进程比较浪费资源,多线程节省资源。
每一个进程中,最少有一个线程,叫做主线程。
线程使用的是第三方库,需要添加#include<pthread.h>头文件,在编译的时候,需要添加 -lpthread参数
安装线程man手册:sudo apt-get install manpages*
1.2 线程创建
1.2.1 pthread_create(线程创建的函数)
#include <pthread.h>
int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void *(*start_routine)(void *),void *arg);
功能:创建线程
参数:
thread:线程号
attr:线程属性 -- 传NULL即可
start_routine:线程体 - 在线程体中定义了线程要执行的任务
arg:给线程传参
返回值:成功返回0,失败返回错误码
1.2.2 线程创建函数的使用示例1(不关注返回值)
#include <my_head.h>
pthread_t tid;
void *thread_func(void *arg){
while (1)
{
printf("线程1\n");
sleep(1);
}
}
int main(int argc,const char *argv[]){
int ret = 0;
ret = pthread_create(&tid,NULL,thread_func,NULL);
if(ret != 0){
printf("创建线程失败:%s\n",strerror(ret));
return -1;
}
while (1)
{
printf("我是主线程\n");
sleep(1);
}
return 0;
}
运行结果:
1.2.3 线程创建函数的使用示例2 (传递参数)
#include <my_head.h>
pthread_t tid1,tid2;
typedef struct Struct{
char name[32];
char sex;
short tall;
}stu_t;
void *thread_func(void *arg){
while(1){
printf("线程id = %d\n",*(int *)arg);
sleep(1);
}
}
void *thread_func2(void *arg){
while (1)
{
printf("%s %c %hd",((stu_t *)(arg))->name,((stu_t *)(arg))->sex,((stu_t *)(arg))->tall);
sleep(1);
}
}
int main(int argc,const char *argv[]){
int ret = 0;
stu_t stu1 = {
.name = "xiaoming",
.sex = 'm',
.tall = 180,
};
stu_t stu2 = {
.name = "hong",
.sex = 'w',
.tall = 170,
};
ret = pthread_create(&tid1,NULL,thread_func2,(void *)&stu1);
if(ret != 0){
printf("创建线程失败:%s\n",strerror(ret));
return -1;
}
while (1)
{
printf("主线程\n");
sleep(1);
}
return 0;
}
运行实例:
1.3 线程的执行顺序问题
没有顺序,时间片轮询,上下文切换
1.4 线程的内存空间问题
#include<my_head.h>
pthread_t tid1,tid2;
int var1 = 100;
void *thread_func(void *arg){
while(1){
printf("var1 = %d\n",var1);//5s之后,输出数值变成200,下面的线程对全局变量数值做了修改
sleep(1);
}
}
void *thread_func2(void *arg){
sleep(5);
var1 = 200;
}
int main(int argc,const char *argv[]){
int ret = 0;
ret = pthread_create(&tid1,NULL,thread_func,NULL);
if(ret != 0){
printf("创建线程失败:%s\n",strerror(ret));
return -1;
}
ret = pthread_create(&tid2,NULL,thread_func2,NULL);
if(ret != 0){
printf("创建线程失败:%s\n",strerror(ret));
return -1;
}
while(1){
// printf("我是主线程....\n");
sleep(1);
}
return 0;
}
1.5 pthread_self(获取线程号)
#include <pthread.h>
pthread_t pthread_self(void);
功能:获取线程的线程号
参数:空
返回值:获取到的线程号,这个函数总是调用成功
pthrread_self使用示例
#include <my_head.h>
pthread_t tid1,tid2;
void *thread_func2(void *arg){
printf("我的线程号%ld\n",pthread_self());
}
int main(int argc,const char *argv[]){
int ret = 0;
ret = pthread_create(&tid2,NULL,thread_func2,NULL);
if(ret != 0){
printf("创建线程失败:%s\n",strerror(ret));
return -1;
}
while(1){
sleep(1);
}
return 0;
}
运行结果:
2.7 pthread_join(线程资源回收)
#include <pthread.h> -- 所需头文件
int pthread_join(pthread_t thread,void **retval);
功能:阻塞回收指定的线程资源
参数:
thread:要回收的现成的线程id
retval:线程退出的状态
返回值:成功返回0,失败返回错误码
pthread_join函数的使用(不传参)
#include <my_head.h>
pthread_t tid1,tid2;
void *thread_func2(void *arg){
printf("我是子线程,我要结束了\n");
pthread_exit(NULL);//传参NULL,不反悔退出状态
}
int main(int argc,const char *argv[]){
int ret = 0;
while(1){
ret = pthread_create(&tid2,NULL,thread_func2,NULL);
if(ret != 0){
printf("创建线程失败:%s\n",strerror(ret));
return -1;
}
pthread_join(tid2,NULL);
sleep(1);
}
return 0;
}
运行结果:
pthread_join 函数的使用(不传参)
#include <my_head.h>
pthread_t tid1,tid2;
void *thread_func2(void *arg){
printf("子进程,我要结束了\n");
pthread_exit(NULL);//传NULL,不返回退出状态
}
int main(int argc,const char *argv[]){
int ret = 0;
while(1){
ret = pthread_create(&tid2,NULL,thread_func2,NULL);
if(ret != 0){
printf("创建线程失败:%s\n",strerror(ret));
return -1;
}
pthread_join(tid2,NULL);//不传参NULL
sleep(1);
}
return 0;
}
运行结果:
pthread_join 函数的使用(传参)
#include <my_head.h>
pthread_t tid1,tid2;
void *thread_func2(void *arg){
int *retval = (int *)malloc(sizeof(int));
*retval = 100;
printf("我是子线程,我要结束了\n");
pthread_exit((void *)retval);
//传NULL,不反悔退出状态
//不可传局部变量的地址,会导致数据错误或者程序崩溃
}
int main(int argc,const char *argv[]){
int ret = 0;
int *retval;
ret = pthread_create(&tid2,NULL,thread_func2,NULL);
if(ret != 0){
printf("创建线程失败%s\n",strerror(ret));
return -1;
}
pthread_join(tid2,(void **)&retval);
printf("retval = %d\n",*retval);
free(retval);
sleep(1);
return 0;
}
运行结果:
1.8 pthread_detach(线程分离)
线程的状态分为两种 分离态 和 结合态。
结合态的线程,需要其他线程调用pthread_join为线程回收资源。
分离态的线程,操作系统会自动为线程回收资源。
线程默认的状态:结合态。
#include <pthread.h> -- 所需头文件
int pthread_detach(pthread_t thread);
功能:将线程设置为分离态
参数:
thread:线程id
返回值:成功返回0,失败返回错误码
#include <my_head.h>
pthread_t tid1,tid2;
void *thread_func2(void *arg){
pthread_detach(pthread_self());
//将线程设为分离态,线程结束之后,才做系统自动为其分配资源
printf("我是子线程,我要结束了\n");
pthread_exit(NULL);//传NULL,不反悔退出状态
}
int main(int argc,const char *argv[]){
int ret = 0;
while(1){
ret = pthread_create(&tid2,NULL,thread_func2,NULL);
if(0 != ret){
printf("创建线程失败:%s\n",strerror(ret));
return -1;
}
sleep(1);
}
}
运行结果: