线程调用
线程创建。
–在进程中只有一个控制线程
–程序开始运行的时候每个进程只有一个线程,它是以单线程方式启动的,在创建多个线程以前,进程的行为与传统的进程没有区别。
–gcc在链接的时候需要增加-lpthread选项。
–创建一个线程调用pthread_create函数。
#include <pthread.h>
int pthread_create(pthread_t *thread,const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);
如果pthread_create成功返回,由thread指向的内存单元被设置为新创建线程的线程ID。
attr参数用于定制各种不同的线程属性。
新创建的线程从start_rtn函数地址开始执行,该函数只有一个void *参数,如果需要向start_rtn函数传递多个参数,就需要把这些参数放到一个结构中,然后把这个结构的地址做为void *传入。
线程创建的时候不能保证哪个先运行。
pthread函数调用失败,返回errno
–注意:每个线程都拥有一份errno副本,不同的线程拥有不同的errno
pthread_create例子
gcc链接时需要加-lpthread选项
void *func(void *arg) { printf("pthread start\n"); return NULL; } int main(int arg, char * args[]) { pthread_t thr_d; int err = pthread_create(&thr_d, NULL, func, NULL); if (err != 0) { printf("create pthread failed\n"); } else { printf("create pthread success\n"); } sleep(1); return 0; }
线程终止。
–任一线程调用了exit函数,整个进程就会终止。
–如果信号默认动作是终止进程,那么信号发送到该线程,整个进程也会被终止。
单个线程通过以下三种方式退出
–线程只是从启动函数中返回,返回值是线程的退出码。
–线程可以被同一进程中的其他线程取消。
–线程调用pthread_exit。
void pthread_exit(void *arg);
arg是个无类型指针,该指针会被其他线程调用pthread_join捕捉。
pthread_exit例子
void *func(void *arg) { printf("pthread start\n"); static int i = 1; pthread_exit(&i); } int main(int arg, char * args[]) { pthread_t thr_d; pthread_create(&thr_d, NULL, func, NULL); sleep(1); return 0; }
int pthread_join(pthread_t th, void **thr_return);。
pthread_join函数用于挂起当前线程,直至th指定的线程终止为止。
如果另一个线程返回值不是NULL,则保存在thr_return地址中。
一个线程所使用的内存资源在应用pthread_join调用之前不会被重新分配,所以对于每个线程必须调用一次pthread_join函数。
其他线程不能对同一线程再应用pthread_join调用。
pthread_join例子
void *func(void *arg) { printf("pthread start\n"); static int i = 0; sleep(2); pthread_exit(&i); } int main(int arg, char * args[]) { pthread_t thr_d; pthread_create(&thr_d, NULL, func, NULL); void *p; pthread_join(thr_d, &p); int *pi = (int *)p; printf("thread exit %d\n", *pi); return 0; }
int pthread_detach(pthread_t th);
pthread_detach函数使线程处于被分离状态。
对于被分离状态的线程,不需要调用pthread_join,如果其他线程调用pthread_join失败,返回EINVAL。
如果不等待一个线程,同时对线程的返回值不感兴趣,可以设置这个线程为被分离状态,让系统在线程退出的时候自动回收它所占用的资源。
一个线程不能自己调用pthread_detach改变自己为被分离状态,只能由其他线程调用pthread_detach。
pthread_detach例子
void *func(void *arg) { printf("pthread start\n"); pthread_exit(NULL); } int main(int arg, char * args[]) { pthread_t thr_d; pthread_create(&thr_d, NULL, func, NULL); pthread_detach(thr_d); sleep(1); return 0; }
int pthread_cancel(pthread_t th);
pthread_cancel函数允许一个线程取消th指定的另一个线程。
函数成功,返回0,否则返回非0。
pthread_cancel例子
void *func(void *arg) { printf("pthread start\n"); while(1) { printf("thread is running\n"); sleep(1); } pthread_exit(NULL); } int main(int arg, char * args[]) { pthread_t thr_d; pthread_create(&thr_d, NULL, func, NULL); pthread_detach(thr_d); sleep(6); pthread_cancel(thr_d); sleep(6); printf("end\n"); return 0; }
int pthread_equal(pthread_t th1,pthread_t th2);
pthread_equal函数比较th1与th2是否为同一个线程,由于不可以将pthread数据类型认为是整数,所以也不能用比较整数的方式比较pthread_t。
如果th1与th2相同,函数返回非0值,如果不同函数返回0。
线程属性
–以前调用pthread_create传入的attr参数都是空指针,而不是指向pthread_attr_t结构的指针。
–可以使用pthread_attr_t结构修改线程默认属性,并把这些属性与创建的线程联系起来
–可以使用pthread_attr_init函数初始化pthread_attr_t结构。
–调用pthread_attr_init以后,pthread_arrt_t的结构所包含的内容就是操作系统实现支持线程所有属性的默认值。如果要修改其中个别属性的值,需要调用其他函数。
int pthread_attr_destroy(pthread_attr_t *attr);
int pthread_attr_init(pthread_attr_t *attr);
函数pthread_attr_init初始化attr结构。
函数pthread_attr_destroy释放attr内存空间。
pthread_attr_t的结构对于应用程序来讲是不透明的,应用程序不需要了解有关结构的内部组成。
以前介绍了pthread_detach函数的概念,可以通过pthread_attr_t在创建线程的时候就指定线程属性为detach,而不用创建以后再去修改线程属性。
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate); 。
函数pthread_attr_setdetachstate把线程属性设置为下面两个合法值之一
值 |
说明 |
PTHREAD_CREATE_DETACHED |
设置线程为分离状态 |
PTHREAD_CREATE_JOINABLE |
设置线程为正常状态 |
pthread_setdetachstate例子
void *func(void *arg) { printf("pthread start\n"); while(1) { printf("thread is running\n"); sleep(1); } pthread_exit(NULL); } int main(int arg, char * args[]) { pthread_t thr_d; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_create(&thr_d, &attr, func, NULL); pthread_attr_destroy(&attr); sleep(2); printf("end\n"); return 0; }