Linux线程
本文最后更新于:2021年4月9日 晚上
概览:Linux线程
线程
进程与线程类似,是允许应用程序并发执行多个任务的一种机制。
一个进程可以包含多个线程。
同一个程序中的所有线程均会独立执行相同程序,且共享同一份全局内存区域,包括初始化数据段、未初始化数据段、以及堆内存段。
- 传统意义上的UNIX进程只是多线程程序的一个特例,该进程只包含一个线程。
进程是CPU分配资源的最小单位,线程则是操作系统调度执行的最小单位。
Linux中线程的本质仍然是进程,线程是轻量级的进程。(LWP:Light Weight Process)
查看执行进程的线程号:
1 |
|
查看当前pthread库的版本
1 |
|
线程和进程的区别
- 信息共享
- 进程间的信息难以共享。由于除去只读代码段外,父子进程并未共享内存,因此必须采用一些进程间通信方式,在进程间进行信息交换。
- 线程之间能够方便、快速地共享信息。只需将数据复制到共享(全局或堆)变量中即可。
- 创建代价
- 调用 fork() 来创建进程的代价相对较高,即便利用写时复制技术,仍然需要复制诸如内存页表和文件描述符表之类的多种进程属性,这意味着 fork() 调用在时间上的开销依然不菲。
- 创建线程比创建进程通常要快10倍甚至更多,线程间是共享虚拟地址空间,无需采用写时复制技术来复制内存,也无需复制页表。
线程共享与非共享的资源
共享资源
- 进程ID和父进程ID
- 进程组ID和会话ID
- 用户ID和用户组ID
- 文件描述符表
- 信号处置
- 文件系统的相关信息:文件权限掩码(umask),当前工作目录
- 虚拟地址空间(除了栈、.text代码段)代码段会发生变化分成一个个的段、栈也是。
- 共享库、堆这些都是共享的。
非共享资源
- 线程ID
- 信号掩码 – 阻塞信号集
- 线程特有数据
- error变量
- 实时调度策略和优先级
- 栈、本地变量和函数的调用链接信息。
注意事项
pthread
不是linux的标准库,需要额外引入一个静态库-lpthread
或者-pthread
编译链接之后才能执行程序。- 一般情况下,main函数所在的线程我们称之为主线程(main线程),其余创建的线程称之为子线程。
- 程序默认只有一个线程,
pthread_create()
函数调用之后,就像fok()一样,产生两个线程。 - 线程回收不一定只能主线程回收其他子线程,任何线程都可以回收其他线程。
- 线程相关函数创建的错误号不同于之前进程中的那些错误号,需要区别对待!
- 可以通过
pthread_self()
函数来获取线程id。 int pthread_equal(pthread_t t1, pthread_t t2);
可以来对比两个线程id是否相同,由于不同的操作系统,其pthread_t
类型实现不太一样,有的是无符号的长整型,有的是使用结构体去实现的,所以使用封装好的函数对比,容易提高代码复用性。
pthread_create 创建线程
1 |
|
实例:
1 |
|
pthread_exit 线程终止
1 |
|
- 即使主线程终止了,也不会影响其他线程的执行。
实例:
1 |
|
pthread_join 连接 【阻塞函数】
1 |
|
retval
是一个二层指针,来保存相关联线程exit退出时的参数。由于exit退出时的参数保存在了
void *retval
之中。要获取上述的那个参数,也需要一个指针来保存,但是我们传递的指针需要接收完结果之后还要能够使用,所以不能使用一个单纯的指针,那样就像是普通的参数传递。
在C语言中要使得传入的参数在函数中改变还能拿得到,使用指针是最好的选择。
例子:
int a = 10; void func(int b){};//想通过func来改变a的值 void func(int *b){} //这样就可以
## pthread_deach 分离线程1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
实例:
```c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
int gloabl = 20;
void *callback(void * arg){
printf("child pthread : %ld\n",pthread_self());
gloabl = 30;//得是全局变量,局部变量在函数结束之后,栈回收,变量随之销毁!
pthread_exit((void *)&gloabl);
}
int main(){
pthread_t tid;
int ret = pthread_create(&tid,NULL,callback,NULL);
if(ret != 0){
printf("error1 : %s\n",strerror(ret));
}
printf("child : %ld , parent: %ld \n",tid,pthread_self());
//回收资源
int * thread_retval;//接收子线程退出的数据
ret = pthread_join(tid,(void **)&thread_retval);
if(ret != 0){
printf("error2 : %s\n",strerror(ret));
}
printf("join data : %d\n",*thread_retval);//30
pthread_exit(NULL);
return 0;
}
1 |
|
实例:
1 |
|
pthread_cancle 取消线程
1 |
|
实例
1 |
|
线程设置属性
1 |
|
应用:
1 |
|
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!