1. 线程概念
线程是轻量级的进程;Linux中,线程本质上仍是进程。
进程是OS分配资源的最小单位,线程是OS调度的最小单位。
NPTL
当前Linux线程库为redHat开发的NPTL,查看本地线程库版本:
getconf GNU_LIBPTHREAD_VERSION
2. 线程特点
(1)轻量级的进程(Light-Weight Process),也有PCB;
(2)无论是创建进程的fork,还是创建线程的pthread_create,底层都是调用内核函数clone;
(3)若复制(深拷贝,但有“COW”优化)父进程地址空间,则为进程;若共享(浅拷贝)父进程地址空间,则为线程。
(4)Linux内核不区分进程和线程,只在上层应用区分;
(5)线程操作函数pthread_*是库函数,而非系统调用。
线程优点
(1)提高并发性;
(2)开销小;
(3)共享数据方便;
线程缺点
(1)库函数,不稳定;
(2)调试困难;
(3)信号支持不好。
3. 线程间共享资源和非共享资源
(1)线程共享资源
① 文件描述符表
② 各信号处理方式
③ 当前工作目录
④ 用户ID和组ID
⑤ 内存地址空间中的 .txt、.data、.bss、.heap、.共享库
(2)线程非共享资源
① 线程id
② 处理器现场和栈指针(内核栈)
③ 线程栈(用户空间栈)
④ errno变量
⑤ 信号屏蔽字
⑥ 调度优先级
线程共享资源测试:
主线程、子线程对全局num、堆区变量修改:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
int num = 100; // 全局变量
void* func(void* arg) {
int* pn = (int*)arg;
printf("修改前, 子线程中的全局变量num = %d, 堆区变量*p = %d\n", num, *pn);
num++;
(*pn)++;
printf("修改后, 子线程中的全局变量num = %d, 堆区变量*p = %d\n", num, *pn);
return NULL;
}
int main(int argc, const char* argv[]) {
pthread_t tid;
int ret = -1;
int* p = NULL;
memset(&tid, 0, sizeof(tid));
// 分配堆空间
p = malloc(sizeof(int));
if (NULL == p) {
perror("malloc");
return 1;
}
memset(p, 0, sizeof(int));
*p = 10;
// 创建一个线程
ret = pthread_create(&tid, NULL, func, (void*)p);
if (0 != ret) {
printf("线程创建失败...\n");
return 1;
}
printf("按回车键继续.\n");
getchar();
printf("修改后, 主线程中的全局变量num = %d, 堆区变量*p = %d\n", num, *p);
free(p); // 只能释放一次,因为堆区是共享的,只有一个*p
return 0;
}
运行结果:
可知同一进程中的线程共享.data区、heap区,此外还共享代码区、.bss区。