转载: https://www.cnblogs.com/jikexianfeng/p/5734855.html
进程原语 | 线程原语 | 描述 |
fork | pthread_create | 创建新的控制流 |
exit | pthread_exit | 从现有的控制流中退出 |
waitpid | pthread_join | 从控制流中得到退出状态 |
atexit | pthread_cancel_push | 注册在退出控制流时调用的函数 |
getpid | pthread_self | 获取控制流的ID |
abort | pthread_cancel | 控制流的非正常退出 |
pthread_create
int pthread_create(pthread_t *thread, pthread_addr_t *arr,void* (*start_routine)(void *), void *arg);
- thread :用于返回创建的线程的ID
- arr : 用于指定的被创建的线程的属性,上面的函数中使用NULL,表示使用默认的属性
- start_routine : 这是一个函数指针,指向线程被创建后要调用的函数
- arg : 用于给线程传递参数,在本例中没有传递参数,所以使用了NULL
线程创建时并不能保证哪个线程会先运行:是新创建的线程还是调用线程。新创建的线程可以访问进程的地址空间,
并且继承调用线程的浮点环境和信号屏蔽字,但是该线程的未决信号集被消除。
单个线程可以通过三种方式退出,在不终止整个进程的情况下停止它的控制流。
(1)线程只是从启动全程中返回,返回值是线程的退出码。
(2)线程可以被同一进程中的其他线程取消
(3)线程调用pthread_exit
void pthread_exit(void *rval_ptr)
rval_ptr是一个无类型指针,与传给启动例程的单个参数类似。进程中的其他线程可以通过调用pthread_join函数访问到这个指针。
int pthread_join(pthread_t thread,void **rval_ptr);
成功返回0,失败返回错误编号
调用线程将一直阻塞,直到指定的线程调用pthread_exit,从启动例程中返回或者被取消。
如果线程只是从它的启动例程返回,rval_ptr将包含返回码。如果线程被取消,由rval_ptr指定的内存单元被置为PTHREAH_CANCELED.
可以通过调用pthread_join自动把线程置于分离状态,这样资源就可以恢复。如果线程已经处于分离状态,pthread_join调用就会失败,返回EINVAL.
如果对线程的返回值并不感兴趣,可以把rval_ptr置为NULL。在这种情况下,调用pthread_join函数将等待指定的线程停止,但并不获取线程的终止状态。
在 调用线程的栈上分配了该结构,那么其他的线程在使用这个结构进内存可能已经改变了。又如,线程在自己的栈上分配了一个结构然后把指向这个结构的指针传给 pthread_exit,那么当调用pthread_join的线程试图使用该结构时,这个栈有可能已经被撤消,这块内存也已另作他用。
例如:#include <stdlib.h>
#include <stdio.h> #include <pthread.h> struct foo { int a, b, c, d; }; void printfoo(const char *s, const struct foo *fp) { printf("%s",s); printf(" structure at 0x%x\n", (unsigned)fp); printf(" foo.a = %d\n", fp->a); printf(" foo.b = %d\n", fp->b); printf(" foo.c = %d\n", fp->c); printf(" foo.d = %d\n", fp->d); } void *thr_fn1(void *arg) { struct foo foo = {1, 2, 3, 4}; printfoo("thread 1:\n", &foo); pthread_exit((void *)&foo); } void *thr_fn2(void *arg) { struct foo fao = { 2,2, 3, 4}; printf("thread 2: ID is %d\n", (unsigned int)pthread_self()); pthread_exit((void *)0); } int main(void) { int err; pthread_t tid1, tid2; struct foo *fp; err = pthread_create(&tid1, NULL, thr_fn1, NULL); if (err != 0) printf("can't create thread 1: %d\n", strerror(err)); err = pthread_join(tid1, (void *)&fp); if (err != 0) printf("can't join with thread 1: %d\n", strerror(err)); sleep(1); printf("parent starting second thread\n"); err = pthread_create(&tid2, NULL, thr_fn2, NULL); if (err != 0) printf("can't create thread 2: %d\n", strerror(err)); sleep(1); printfoo("parent:\n", fp); exit(0); }
void pthread_cleanup_push(void (*rtn)(void *),void *arg);
void pthread_cleanup_pop(int execute);
当线程执行以下动作时调用清理函数,调用参数为arg,清理函数rtn的调用顺序是由pthread_cleanup_push函数来安排的。
1.调用pthread_exit时。2.响应取消请求时。3.用非零execute参数调用pthread_cleanup_pop时。
如果execute参数置为0,清理函数将不被调用。无论哪种情况,pthread_cleanup_pop都将删除上次pthread_clean_push调用建立的清理处理程序。
实例:
#include <stdlib.h> #include <stdio.h> #include <pthread.h> void cleanup(void *arg) { printf("cleanup: %s\n", (char *)arg); } void *thr_fn1(void *arg) { printf("thread 1 start\n"); pthread_cleanup_push(cleanup, "thread 1 first handler"); pthread_cleanup_push(cleanup, "thread 1 second handler"); printf("thread 1 push complete\n"); if (arg) return((void *)1); // pthread_exit((void *)2); pthread_cleanup_pop(0); pthread_cleanup_pop(0); // return((void *)1); pthread_exit((void *)2); } void *thr_fn2(void *arg) { printf("thread 2 start\n"); pthread_cleanup_push(cleanup, "thread 2 first handler"); pthread_cleanup_push(cleanup, "thread 2 second handler"); printf("thread 2 push complete\n"); if (arg) pthread_exit((void *)2); pthread_cleanup_pop(0); pthread_cleanup_pop(0); pthread_exit((void *)2); } int main(void) { int err; pthread_t tid1, tid2; void *tret; err = pthread_create(&tid1, NULL, thr_fn1, (void *)1); if (err != 0) printf("can't create thread 1: %c\n", strerror(err)); err = pthread_create(&tid2, NULL, thr_fn2, (void *)1); if (err != 0) printf("can't create thread 2: %c\n", strerror(err)); err = pthread_join(tid1, &tret); if (err != 0) printf("can't join with thread 1: %c\n", strerror(err)); printf("thread 1 exit code %d\n", (int)tret); err = pthread_join(tid2, &tret); if (err != 0) printf("can't join with thread 2: %c\n", strerror(err)); printf("thread 2 exit code %d\n", (int)tret); exit(0); }