NB:标准C是没有线程支持的,要在C中使用多线程,需要使用POSIX接口。本文介绍POSIX 多线程的基本函数。
1. pthread_create
函数原型:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
函数功能:创建新的线程。
参数说明:
- 函数成功后,thread参数保存新线程的线程号。
- 第二个参数用于设置新创建线程的一些属性。如果使用系统默认的值,则可设为NULL。
- 第三个参数是一个函数指针,是新创建线程的入口地址。该函数只能有一个无类型指针参数arg,并且返回值为void *.
- 第四个参数即是入口函数的参数。如果有多个参数,需要将多个参数放到一个结构中,然后把结构的地址传给入口函数。若函数没有参数,则该参数可设为NULL。
返回值:成功返回0;失败返回错误码,失败的时候thread的值时未定义的。
使用注意点:
- 线程创建时并不能保证哪个线程会先运行:是新创建的线程还是调用线程(主进程)。
- 新创建的线程可以访问调用线程的地址空间,并且继承调用线程的浮点环境和信号屏蔽字,但是该线程的未决信号集被清除。
- 函数调用失败时会返回错误码,但并不会设置errno。
2. pthread_equal
函数原型:
int pthread_equal(pthread_t t1, pthread_t t2);
函数功能:比较线程号是否相等。线程号使用pthread_t类型表示,一般都实现为无符号长整形(unsigned long int)。但是可移植的操作系统实现不能把它作为整数处理(即不能用==来比较两个线程号是否相等),所以专门实现了一个函数来比较线程号的值。
参数说明:两个线程的线程号。
返回值:t1和t2相等,返回非0;否则返回0.
3. pthread_self
函数原型:
pthread_t pthread_self(void);
函数功能:获取本线程线程号,gettid函数也可以实现该功能。
返回值:函数总是成功,返回调用者的线程号。
4. pthread_exit
函数原型:
void pthread_exit(void *retval);
函数功能:退出本线程。
参数说明:参数以为一个无类型指针,用于向其他线程(有的话)返回退出状态。如果不关心退出状态,可以将参数设为NULL。
返回值:函数总是成功,且不是返回给调用者(而是pthread_join,如果有的话)。
关于线程终止的注意点:如果进程中任一线程调用了exit、_Exit或者_exit,那么整个进程就会终止。与此类似,如果一个信号的默认动作是终止进程,那么,把该信号发送到线程会终止整个进程。单个线程可以通过下列三种方式退出(只退出线程,不终止进程):
- 线程只是从启动例程中返回,返回值是线程的退出码。比如执行了return语句。
- 线程可以被同一进程中的其他线程取消,见后面的pthread_cancel函数。
- 线程调用pthread_exit函数。
5. pthread_cancel
函数原型:
int pthread_cancel(pthread_t thread);
函数功能:请求取消同一进程中的其他线程。默认情况下,pthread_cancel函数会使得由thread标识的线程的行为表现为如同调用了参数为PTHREAD——CANCELED的pthread_exit函数,但是,线程可以选择忽略取消方式或是控制取消方式。
返回值:成功返回0,失败返回非0。
NB:pthread_cancel函数并不等待线程终止,它仅仅提出请求。
6. pthread_cleanup_push和pthread_cleanup_pop
函数原型:
void pthread_cleanup_push(void (*routine)(void *), void *arg); void pthread_cleanup_pop(int execute);
函数功能:线程可以安排它退出时需要调用的函数,这样的函数称为线程清理程序(thread cleanup handler)。线程可以建立多个清理程序。处理程序记录在栈中,也就是说它们的执行顺序与它们的注册顺序相反。
当线程执行以下动作时调用清理函数,调用参数为arg,清理函数rtn的调用顺序由pthread_cleanup_push来安排:
- 调用pthread_exit时;
- 响应取消请求时;
- 用非0 execute参数调用pthread_cleanup_pop时
如果execute设置为0,清理函数将不被调用。无论哪种情况,pthread_cleanup_pop都将删除上次pthread_cleanup_push调用建立的处理程序。
7. pthread_join
函数原型:
int pthread_join(pthread_t thread, void **retval);
函数功能:等待某一个线程退出。调用线程将一直阻塞,直到thread指定的线程调用pthread_exit、从启动例程返回或被取消。如果线程只是从它的启动例程返回,retval将包含返回码。如果线程被取消,则retval的值为PTHREAD_CANCELED。如果对线程的返回值不感兴趣,可以将retval置为NULL。这样将只等待指定线程终止。
调用pthread_join会自动把线程设置为分离状态,这样资源就可以恢复。如果线程已经处于分离状态,pthread_join调用就会失败,返回EINVAL。
返回值:成功返回0,失败返回错误码。
8. pthread_detach
函数原型:
int pthread_detach(pthread_t thread);
函数功能:使thread指定的线程处于分离状态。
返回值:成功返回0,失败返回错误码。
NB:当一个线程处于非分离状态时,我们称它是joinable的,也就是说我们可以调用pthread_join函数来等待线程退出,并获得退出状态。当线程处于分离状态时,我们称它是 not joinable的,也就是说我们不能调用pthread_join函数来等待线程退出。处于分离状态的线程退出后,会马上自动将其资源释放给操作系统。
最后附上一个程序实例:
/* * common.h * * Created on: 2015-6-16 * Author: allan */ #ifndef COMMON_H_ #define COMMON_H_ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #endif /* COMMON_H_ */ /* * pthread.c * * Created on: 2015-6-16 * Author: allan */ #include "common.h" /* 线程1入口函数 */ void* thr_fn1(void *arg) { pthread_t tid1; tid1 = pthread_self(); printf("thread 1 is running, tid = %ldn", tid1); return ((void*)0); } /* 线程2入口函数 */ void* thr_fn2(void *arg) { pthread_t tid2; tid2 = pthread_self(); printf("thread 2 is running, tid = %ldn", tid2); sleep(3); //return ((void*)0); // 正常线程返回 //exit(0); // 会导致整个进程退出 pthread_exit((void*)2); // 退出 } /* 驱动例程 */ int pthread_driver(void) { pthread_t tid1, tid2; int err, is_equal; /* 创建线程1 */ err = pthread_create( &tid1, NULL, thr_fn1, NULL); if (err) { printf("pthread_create errorn"); return EXIT_FAILURE; } /* 创建线程2 */ err = pthread_create( &tid2, NULL, thr_fn2, NULL); if (err) { printf("pthread_create errorn"); return EXIT_FAILURE; } /* 判断线程1和线程2线程号是否相等 */ is_equal = pthread_equal( tid1, tid2 ); printf("is_equal = %dntid1 = %ldttid2 = %ldn", is_equal, tid1, tid2); void *retval; /* 主线程等待线程2退出,并获取其退出码 */ err = pthread_join(tid2, &retval); if (err) { printf("pthread_join errorn"); return EXIT_FAILURE; } printf("thread 2 return value = %dn", (int)retval); /* 等待一段时间,防止主线程先于线程1退出(因为对线程2调用了pthread_join,所以主线程肯定不会先于线程2退出)*/ sleep(10); return EXIT_SUCCESS; } /* * main.c * * Created on: 2015-6-16 * Author: allan */ #include "common.h" int main(int argc, char *argv[]) { #if 0 if (pthread_driver()) { printf("pthread_driver failed.n"); return EXIT_FAILURE; } #endif if (pthread_exit_bug_driver()) { printf("pthread_exit_bug_driver failed.n"); return EXIT_FAILURE; } return EXIT_SUCCESS; }
评论已关闭