1. 线程
线程是一个轻量化的进程,关于进程与线程的详细概念参见:
进程与线程
线程相比与进程而言,其控制和调度更加灵活,由于同一进程的多个线程共享同一地址空间,因此Text Segment、Data Segment都是共享的,如果定义一个函数,在各线程中都可以调用,如果定义一个全局变量,在各线程中都可以访问到,除此之外,各线程还共享以下进程资源和环境:
文件描述符表
每种信号的处理方式(SIG_IGN、SIG_DFL或者自定义的信号处理函数)
当前工作目录
用户id和组id
但有些资源是每个线程各有一份的:
线程id
上下文,包括各种寄存器的值、程序计数器和栈指针
栈空间
errno变量
信号屏蔽字
调度优先级
2. 创建线程
在Linux中创建线程需要用到pthread_create函数:
#include
int pthread_create(pthread_t *restrict ptid,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void*), void *restrict arg);
头文件:pthread.h
返回值:
成功:0
失败:errno
错误号存放在errno中
参数解析:
ptid: 线程id
attr:线程属性,本章不深入讨论线程属性
start_routine: 线程入口函数,线程启动时,自动执行此函数.注意返回值为void *。这是一个函数指针,关于函数指针参见C函数指针
当start_routine返回时,此线程结束,其它线程可以调用pthread_join得到start_routine的返回值。
arg:start_routine 的参数, 注意其类型为void*
一个简单的例子:
#include
#include
#include
#include
#include
pthread_t ntid;
void printids(const char *s)
{
pid_t pid;
pthread_t tid;
pid = getpid();
tid = pthread_self();
printf("%s pid %u tid %u (0x%x)\n", s, (unsigned int)pid,
(unsigned int)tid, (unsigned int)tid);
}
void *thr_fn(void *arg)
{
printids(arg);
return NULL;
}
int main(void)
{
int err;
err = pthread_create(&ntid, NULL, thr_fn, "new thread: ");
if (err != 0) {
fprintf(stderr, "can't create thread: %s\n", strerror(err));
exit(1);
}
printids("main thread:");
sleep(1);
return 0;
}
函数运行结果:
$ gcc main.c -lpthread
$ ./a.out
main thread: pid 7398 tid 3084450496 (0xb7d8fac0)
new thread: pid 7398 tid 3084446608 (0xb7d8eb90)
注意:多线程编程需要用到libpthread库,所以编译时必须加上 -lpthread
pid(): 获取进程id,
pthread_self():获取线程id。
3. 终止线程
3.1 终止线程,不终止进程
(1)从线程函数return。这种方法对主线程不适用,从main函数return相当于调用exit。
(2)一个线程可以调用pthread_cancel终止同一进程中的另一个线程。
(3)线程可以调用pthread_exit终止自己。
pthread_exit
#include
void pthread_exit(void *value_ptr);
头文件:pthread.h
返回值:void
参数解析:
value_ptr是void *类型,和线程函数返回值的用法一样,其它线程可以调用pthread_join获得这个指针。
注意:pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配
pthread_jion
#include
int pthread_join(pthread_t tid, void **value_ptr);
头文件:pthread.h
返回值:
成功:0
失败:errno
参数解析: tid: 被终止的线程id
value_ptr: 终止状态。
调用该函数的线程将挂起等待,直到id为thread的线程终止。
value_ptr:
(1)tid线程通过return返回,**value_ptr=tid返回值。
(2)tid线程被别的线程调用pthread_cancel异常终止掉,**value_ptr=PTHREAD_CANCELED。
(3)tid线程是自己调用pthread_exit终止的,value_ptr所指向的单元存放的是传给pthread_exit的参数。
3.2 thread detach
一般情况下,线程终止后,其终止状态一直保留到其它线程调用pthread_join获取它的状态为止。但是线程也可以被置为detach状态,这样的线程一旦终止就立刻回收它占用的所有资源,而不保留终止状态。不能对一个已经处于detach状态的线程调用pthread_join,这样的调用将返回EINVAL。对一个尚未detach的线程调用pthread_join或pthread_detach都可以把该线程置为detach状态,也就是说,不能对同一线程调用两次pthread_join,或者如果已经对一个线程调用了pthread_detach就不能再调用pthread_join了。
#include
int pthread_detach(pthread_t tid);
返回值:成功返回0,失败返回错误号。
4. 参考文献
Linux C编程一站式学习