线程的概念
一、线程的定义
线程是进程中的⼀个执行单元,负责当前进程中程序的执行,⼀个进程中至少有⼀个线程
⼀个进程中是可以有多个线程
多个线程共享同一个进程的资源,每个线程参与操作系统的统一调度
可以简单理解:
进程
=
进程资源
+
主线程
+
子线程
+......
二、线程与进程
线程与进程区别
内存空间
一个进程中多个线程共享同一个内存空间
多个进程拥有独立的内存空间
进程
/
线程间通讯
线程间通讯方式简单
进程间通讯方式复杂
并发操作,线程比进程更节约资源
总结:
联系紧密的任务在并发时优先选择多线程,如果任务之间比较独立,在并发时建议选择多进程。
三、线程资源
共享进程的资源
同一块地址空间
文件描述符表
每种信号的处理方式(如:
SIG_DFL,SIG_IGN
或者自定义的信号优先级)
当前工作目录
用户
id
和组
id
独立的资源
线程栈
每个线程都有私有的上下文信息。
线程
ID
寄存器的值
errno
变量
信号屏蔽字以及调度优先级
线程相关的命令
在
Linux
系统有很多命令可以查看进程,例如
pidstat
、
top
、
ps
,也可以查看一个进程下的线程
一、pidstat
ubuntu
下安装
sysstat
工具后,可以支持
pidstat
sudo apt install sysstat
选项
-t:
显示指定进程所关联的线程
-p:
指定进程
pid
示例:使用
pidstat
命令查看某一个进程下的线程
step 1 :
运行
sem
程序
,
此程序包含两个进程
step 2 :
查看
sem
进程所对应的
id
step 3 :
使用
pidstat
命令查看相应进程的线程
二、top 命令
top
命令查看某一个进程下的线程,需要用到
-H
选项在结合
-p
指定
pid
示例:使用
top
命令查看某一个进程下的线程
sudo apt install sysstat
选项
-t:
显示指定进程所关联的线程
-p:
指定进程
pid
top
-H -p
3027
三、ps命令
ps
命令结合
-T
选项就可以查看某个进程下所有线程
创建线程
一、线程创建
创建线程调用
pthread_create
函数
函数头文件
#include <pthread.h>
函数原型
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *
(*start_routine) (void *), void *arg);
函数功能
创建一个子线程
函数参数
thread:线程ID变量指针
attr:线程属性,默认属性可设置为NULL
start_routine:线程执行函数
arg:线程执行函数的参数
函数返回值
成功:返回 0
失败:返回 错误码
Tips
:
typedef unsigned long int pthread_t;
一旦子线程创建成功,则会被独立调度执行,并且与其他线程
并发执行
在编译时需要链接
-lpthread
[Compile and link with -pthread]
示例:创建一个线程,打印线程
ID
问题:
1.
在编译时出现下面的错误
implicit declaration of function 'pthread_create'
解决办法:
pthread
库不是
Linux
系统默认的库,编译的时候需要加上库
-lpthread
2.
程序执行的结果中只打印了
tid,
子线程没有执行
原因是
子线程还没有来得及执行,主线程已经结束,导致其他子线程都必须结束
解决办法:
保证主线程不先于子线程结束
(
23
章节详解)
线程的等待、退出和分离
一、线程退出
线程退出使用
pthread_exit
函数
函数头文件
#include <pthread.h>
函数原型
void pthread_exit(void *retval);
函数功能
让线程退出,并返回值
函数参数
retval:线程返回值,通过指针传递
函数返回值
成功:返回 0
失败:返回 -1
Tips:
1.
当主线程调用
pthread_exit
函数时,进程不会结束,也不会导致其他子线程退出
2.
任何线程调用
exit
函数会让进程结束
二、线程等待
主线程需要等待子线程退出,并释放子线程资源
线程等待调用
pthread_join
函数,会阻塞调用线程
函数头文件
#include <pthread.h>
函数原型
int pthread_join(pthread_t thread, void **retval);
函数功能
等待子线程退出,并释放子线程资源
函数参数
thread:线程 ID
retval:获取线程退出值的指针
函数返回值
成功:返回0
失败:返回错误码
例代码:创建一个子线程,主线程等待子线程退出
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
// 线程执行函数
void* do_thread_function(void* args)
{
printf("do thread ....\n");
pthread_exit(NULL);
}
int main()
{
pthread_t thread_id;
int result =pthread_create(&thread_id,NULL,do_thread_function,NULL);
if(result!=0)
{
fprintf(stderr,"pthread error:%s\n",strerror(result));
exit(EXIT_FAILURE);
}
printf("thread id is %ld\n",thread_id);
pthread_join(thread_id,NULL);
return 0;
}
三、线程分离
线程分为可结合的与可分离的
可结合
可结合的线程能够被其他线程收回其资源和杀死;在被其他线程回收之前,它的存储器资源
(如栈)是不释放的。
线程创建的默认状态为可结合的,可以由其他线程调用
pthread_join
函数等待子线程退出并
释放相关资源
可分离
不能被其他线程回收或者杀死的,
该线程的资源在它终止时由系统来释放
。
线程分离调用
pthread_detach
函数
函数头文件
#include <pthread.h>
函数原型
int pthread_detach(pthread_t thread);
函数功能
设置在线程退出后,由操作系统自动释放该线程的资函数参数
thread:线程ID
函数返回值
成功:返回0
失败:返回-1源
注意:
线程分离函数不会阻塞线程的执行
示例代码:创建一个线程,并设置线程为可分离状态
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
// 线程执行函数
void* do_thread_function(void* args)
{
printf("do thread ....\n");
pthread_exit(NULL);
}
int main()
{
pthread_t thread_id;
int result =pthread_create(&thread_id,NULL,do_thread_function,NULL);
if(result!=0)
{
fprintf(stderr,"pthread error:%s\n",strerror(result));
exit(EXIT_FAILURE);
}
printf("thread id is %ld\n",thread_id);
//线程分离
pthread_detach(thread_id);
return 0;
}
补充: