线程原语
线程概念
线程(thread),有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。更多详细解释看百度百科:线程。
在Linux shell下通过命令 $ ps -Lf pid 查看指定pid号下的所有线程。
线程之间的共享与非共享
这里的线程是指同一进程下的线程。
共享:
1.文件描述符表
2.每种信号的处理方式
3.当前工作目录
4.用户ID和组ID
5.内存地址空间
非共享:
1.线程id
2.处理器现场和栈指针(内核栈)
3.独立的栈空间(用户空间栈)
4.errno变量
5.信号屏蔽字
6.调度优先级
线程原语
通过命令 $ man -k pthread 查看系统下与线程有关的所有函数。
一般的,把main函数称作主线程或主控线程,其它线程都称作是子线程。
创建线程
#include<pthread.h> int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
pthread_t *thread:传递一个pthread_t变量地址进来,用于保存新线程的tid(线程ID)
const pthread_attr_t *attr:线程属性设置,如使用默认属性,则传NULL
void *(*start_routine)(void *):函数指针,指向新线程应该加载执行的函数模块
void *arg:指定线程将要加载调用的那个函数的参数
返回值:成功返回0,失败返回错误号。以前学过的系统函数都是成功返回0,失败返回-1,而错误号保存在全局变量errno中,而pthread库的函数都是通过返回值返回错误号,虽然每个线程也都有一个errno,但这是为了兼容其它函数接口而提供的,pthread库本身并不使用它,通过返回值返回错误码更加清晰。
Compile and link with -lpthread.
typedef unsigned long int pthread_t; //在不同的系统中pthread_t可能会有不同的实现
结束线程
如果需要只终止某个线程而不终止整个进程,可以有三种方法:
1.return。这种方法对主控线程不适用,从main函数return相当于调用exit。
2.一个线程可以调用pthread_cancel终止同一进程中的另一个线程。
#include <pthread.h> int pthread_cancel(pthread_t thread);
被取消的线程,退出值,定义在Linux的pthread库中常数PTHREAD_CANCELED的值是-1。可以在头文件pthread.h中找到它的定义:#define PTHREAD_CANCELED ((void *) -1)。也就是说,被pthread_cancel结束的线程,退出值,都是-1。
同一进程的线程间,pthread_cancel向另一线程发终止信号。系统并不会马上关闭被取消线程,只有在被取消线程下次系统调用时,才会真正结束线程。或调用pthread_testcancel,让内核去检测是否需要取消当前线程。
3.线程可以调用pthread_exit终止自己。
#include <pthread.h> void pthread_exit(void *retval); void *retval:线程退出时传递出的参数,可以是退出值或地址,如是地址时,不能是线程内部申请的局部地址。
在任何地方调用exit,都会使整个进程退出。
线程id
#include <pthread.h> pthread_t pthread_self(void); RETURN VALUE This function always succeeds, returning the calling thread’s ID.
在线程中使用pthread_self,获取线程id。
回收线程
#include <pthread.h> int pthread_join(pthread_t thread, void **retval); pthread_t thread:回收线程的tid void **retval:接收退出线程传递出的返回值 返回值:成功返回0,失败返回错误号
同进程类似,线程退出后,同样需要进行回收,所以pthread_join类似于wait。调用该函数的线程将挂起等待,直到id为thread的线程终止。thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,总结如下:
- 如果thread线程通过return返回,retval所指向的单元里存放的是thread线程函数的返回值。
- 如果thread线程被别的线程调用pthread_cancel异常终止掉,retval所指向的单元里存放的是常数PTHREAD_CANCELED。
- 如果thread线程是自己调用pthread_exit终止的,retval所指向的单元存放的是传给pthread_exit的参数。
如果对thread线程的终止状态不感兴趣,可以传NULL给retval参数。
代码示例
使用return和pthread_exit结束进程
//thread_exit.c #include <stdio.h> #include <unistd.h> #include <pthread.h> void *fun_1(void *argv) { printf("Hello %s,my thread id is %x\n", (char*)argv, pthread_self()); sleep(1); //pthread_exit((void*)1); return (void*)1; } void *fun_2(void *argv) { printf("Hello %c, my thread id is %x\n", (char)argv, pthread_self()); sleep(2); pthread_exit((void*)"David"); } int main(void) { int *ret1; char *ret2; pthread_t tid1, tid2; pthread_create(&tid1, NULL, fun_1, (void*)"zhangxiang"); pthread_create(&tid2, NULL, fun_2, (void*)‘D‘); pthread_join(tid1, (void*)&ret1); pthread_join(tid2, (void*)&ret2); printf("thread %x exit with %x\n", tid1, ret1); printf("thread %x exit with %s\n", tid2, ret2); return 0; } $ gcc thread_exit.c -lpthread $ ./a.out Hello D, my thread id is 745e9700 Hello zhangxiang, my thread id is 74fea700 thread 74fea700 exit with 1 thread 745e9700 exit with David
使用pthread_cancel终止另一个线程
//thread_cancel.c #include <stdio.h> #include <pthread.h> void *fun(void *argv) { printf("thread %x running\n", pthread_self()); pthread_exit((void*)0); } int main(void) { pthread_t tid; void *ret; pthread_create(&tid, NULL, fun, NULL); pthread_join(tid, &ret); printf("thread %x exit with %d\n", tid, (int)ret); pthread_create(&tid, NULL, fun, NULL); pthread_cancel(tid); pthread_join(tid, &ret); printf("thread %x exit with %d\n", tid, (int)ret); return 0; } $ gcc thread_cancel.c -lpthread $ a.out thread 96da9700 running thread 96da9700 exit with 0 thread 96da9700 running thread 96da9700 exit with -1
既可以在主线程中使用pthread_cancel终止子线程,也可以在子线程中终止另一个子线程。
版权声明:本文为博主原创文章,转载,请注明出处。