线程基本知识
1. 创建线程后,地址空间不会发生改变
2. 同时该创建线程的进程退化称为主线程
3. 创建出的子线程和主线程公用地址空间
4. 主线程和子线程有各自独立的pcb
子线程pcb从主线程拷贝而来
5. 同一进程下的多个线程之间共享除栈数据外的其他用户区数据。
栈区会平均划分。线程之间可以通过全局变量和堆通信
6. 在Linux下,线程称为轻量级进程。对于内核而言,认为一个pcb就是一个进程。
线程号和线程ID
1. 线程号和线程ID是有区别的 -- 线程号由内核识别,用户识别线程ID
2. 查看线程id
a. 找到该线程的进程pid
b. 使用命令ps -Lf <进程pid号>
c. LWP为线程id
多进程与多线程
1. 一个单独的线程可以看作一个进程
2. 多进程:
始终共享:代码;文件描述符;内存映射区
3. 多线程:
始终共享:堆;全局变量
4. 线程节约资源
创建线程
1. 函数原型:<pthread.h>
int pthread_create(pthread_t *thread,
const pthread_attr_t *arr,
void *(*start_routine)(void *),
void *arg
);
2. 参数:
thread:线程ID -- 一个无符号长整型数
arr:线程属性 -- 如果子线程设置了分离属性,子线程可以自己释放自己。没有要求可以为NULL。
start_routine:函数指针 -- 创建出的线程所需要执行的操作的函数
arg:回调函数的参数 -- 即创建出的线程执行函数时,会将参数传给内部
3. 返回值
0:创建正确
>0:错误号。通过错误号来查看错误信息 -- 调用函数char *strerror(int errnum)来查看信息
4. 例如:
//线程回调函数
//返回类型为void *,参数类型为void *
void *myfun(void *arg)
{
printf("child thread id = %ld\n", pthread_self());
return NULL;
}
pthread_t pthid;
pthread_create(&pthid, NULL, myfun, NULL);
printf("parent thread id = %ld\n", pthread_self());
sleep(1);//当主线程结束后会强制结束子线程,因此等待子线程输出
5. arg参数传递应该注意传递址还是传值
避免由于传地址时,cpu被抢占,使得原来的地址发生变化
6. 命令行编译
gcc xxpthread_create.c -lpthread
线程退出函数:如果想让某线程退出而不影响其他线程,则需要使用函数
1. 函数原型:
<退出单一线程>
void pthread_exit(void *retval);
2. 参数:
retval:线程退出过程中可以携带信息,该指针指向信息的内存块地址
要么指向全局的内存地址,或者堆的内存地址
回收子线程函数
1. 函数原型:
<阻塞等待>
int pthread_join(pthread_t thread, void **retval);
2. 参数
thread:要回收的子线程的线程ID
retval:传出参数 -- 使用方法:void *ptr; pthread_join(thread, &ptr);
ptr指向一块包含信息的地址
3. 由主线程调用该函数
线程分离
1. 函数原型:
int pthread_detach(pthread_t thread);
2. 参数:
thread:子线程ID
3. 注意:
a. 调用该函数后,子线程会自动回收自己的pcb
b. 调用了该函数后,不再需要使用pthread_join
c. 一般使用pthread_create中设置属性的方式来分离子线程
杀死(取消)线程
1. 函数原型:
int pthread_cancel(pthread_t thread);
2. 参数:
thread:需要杀死的线程ID
3. 注意:
如果要实现杀死线程ID指定线程,必须在该线程内部实现具有系统调用的函数。
例如:
void *myfunc(void *arg)
{
while(1)
{
int i;
i = 10;
}
return NULL;
}
该子线程的回调函数没有系统调用的点,因此pthread_cancel并不会杀死该线程。
4. 设置取消点
pthread_testcancel();
该函数无其他作用,只是设置一个系统调用的点,用于杀死线程。
判断线程ID是否相等(预留函数) – pthread_equal 设置线程分离属性
1. 线程属性类型:
pthread_arrt_t arr;
2. 对线程属性初始化
int pthread_attr_init(pthread_attr_t *attr);
3. 设置线程分离属性:
a. 函数原型:
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
b. 参数:
attr:属性类型变量的地址
detachstate:PTHREAD_CREATE_DETACHED(分离)
PTHREAD_CREATE_JOINABLE(不分离)
4. 使用属性设置后,最后需要释放属性变量的空间
int pthread_attr_destroy(pthread_attr_t *attr);