线程的概念
每个用户进程有自己的虚拟地址空间。
系统为每个用户进程创建一个 task_struct 来描述该进程 struct task_struct。
task_struct 和地址空间映射表一起用来表示一个进程。
由于进程的虚拟地址空间是私有的,因此进程切换开销很大。
为了提高系统的性能,linux 引入轻量级进程,起名为线程。
在同一个进程中创建的线程共享该进程的地址空间。
Linux里同样用 task_struct 来描述一个线程。
总结:
-
通常线程指的是共享相同虚拟地址空间的多个任务。
-
使用多线程,大大提高了任务切换的效率。
-
每个进程中至少有一个线程,就是主线程,还可以产生多个线程。
-
共享4G内存空间,线程切换只需要虚拟CPU(寄存器)。
-
进程代表资源分配的最小单位 线程是最小的调度单位。
一个进程中的多个线程共享以下资源:
-
可执行的指令。
-
静态数据。
-
进程中打开的文件描述符。
-
信号处理函数。
-
当前工作目录。
-
用户ID。
-
用户组ID。
每个线程私有的资源如下:
-
线程ID(TID)。
-
PC(程序计数器)和相关寄存器。
-
堆栈(局部变量、返回地址)。
-
错误号(errno)。
-
信号掩码和优先级。
-
执行状态和属性。
创建线程
#include <pthread.h>
pthread_t tid; //线程号
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
功能:创建线程参数:
thread: &tid 线程号的地址
attr: NULL 线程函数默认的属性
start_routine: 线程函数的函数名
arg: 给线程函数传递的参数 NULL返回值:
成功:0
失败:-1
回收线程资源
int pthread_join(pthread_t thread, void **retval);
功能:主线程等待子线程结束,然后回收资源
参数:
thread: tid
retval: NULL (接收子线程结束的返回值)
返回值:
成功:0
失败:-1
---------------------------------------------------------------------------------
int pthread_detach(pthread_t thread);
功能:主线程和子线程分离开来,系统自动回收资源(非阻塞)
参数:
thread: tid
返回值:
成功:0
失败:-1
结束当前子线程
void pthread_exit(void *retval);
功能:结束当前进程并返回值
参数:
retval:void *
retval 是 void* 类型的指针,可以指向任何类型的数据,它指向的数据将作为线程退出时的返回值。如果线程不需要返回任何数据,将 retval 参数置为 NULL 即可。
通过在主线程(main() 函数)调用 pthread_join() 函数,可以获取线程返回的 retval 数据。
#include <stdio.h>
#include <pthread.h>
// 线程要执行的函数,arg 用来接收线程传递过来的数据
void *ThreadFun(void *arg)
{
// 终止线程的执行,将“abc”返回
pthread_exit("abc"); //返回的字符串存储在常量区,并非当前线程的私有资源
printf("*****************"); //此语句不会被线程执行
}
int main()
{
int res;
// 创建一个空指针
void * thread_result;
// 定义一个表示线程的变量
pthread_t myThread;
res = pthread_create(&myThread, NULL, ThreadFun, NULL);
if (res != 0) {
printf("线程创建失败");
return 0;
}
// 等待 myThread 线程执行完成,并用 thread_result 指针接收该线程的返回值
res = pthread_join(myThread, &thread_result);
if (res != 0) {
printf("等待线程失败");
}
// 打印子线程的返回值
printf("%s", (char*)thread_result);
return 0;
}
pthread_exit() 函数只会终止当前线程,不会影响其它线程的执行。此外,pthread_exit() 函数还会自动调用线程清理程序(本质是一个由 pthread_cleanup_push() 指定的自定义函数),而 return 不具备这个能力。
关闭其他子线程
int pthread_cancel(pthread_t thread);
功能:结束其他子线程
参数:
thread:thread
一个线程还可以向另一个线程发送“终止执行”的信号,这时就需要调用 pthread_cancel() 函数。
对于接收 Cancel 信号后结束执行的目标线程,等同于该线程自己执行如下语句:
pthread_exit(PTHREAD_CANCELED);
也就是说,当一个线程被强制终止执行时,它会返回 PTHREAD_CANCELED 这个宏。