• linux c学习笔记----线程创建与终止


    进程原语 线程原语 描述
    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>
     1 #include <stdio.h>  
     2 #include <pthread.h>  
     3   
     4 struct foo {  
     5     int a, b, c, d;  
     6 };  
     7   
     8 void printfoo(const char *s, const struct foo *fp)  
     9 {  
    10     printf("%s",s);  
    11     printf("  structure at 0x%x
    ", (unsigned)fp);  
    12     printf("  foo.a = %d
    ", fp->a);  
    13     printf("  foo.b = %d
    ", fp->b);  
    14     printf("  foo.c = %d
    ", fp->c);  
    15     printf("  foo.d = %d
    ", fp->d);  
    16 }  
    17   
    18 void *thr_fn1(void *arg)  
    19 {  
    20     struct foo  foo = {1, 2, 3, 4};  
    21   
    22     printfoo("thread 1:
    ", &foo);  
    23     pthread_exit((void *)&foo);  
    24 }  
    25   
    26 void *thr_fn2(void *arg)  
    27 {  
    28     struct foo  fao = { 2,2, 3, 4};  
    29     printf("thread 2: ID is %d
    ", (unsigned int)pthread_self());  
    30     pthread_exit((void *)0);  
    31 }  
    32   
    33 int main(void)  
    34 {  
    35     int         err;  
    36     pthread_t   tid1, tid2;  
    37     struct foo  *fp;  
    38   
    39     err = pthread_create(&tid1, NULL, thr_fn1, NULL);  
    40     if (err != 0)  
    41         printf("can't create thread 1: %d
    ", strerror(err));  
    42     err = pthread_join(tid1, (void *)&fp);  
    43     if (err != 0)  
    44         printf("can't join with thread 1: %d
    ", strerror(err));  
    45     sleep(1);  
    46     printf("parent starting second thread
    ");  
    47     err = pthread_create(&tid2, NULL, thr_fn2, NULL);  
    48     if (err != 0)  
    49         printf("can't create thread 2: %d
    ", strerror(err));  
    50     sleep(1);  
    51     printfoo("parent:
    ", fp);  
    52     exit(0);  
    53 }  
     
    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调用建立的清理处理程序。
    实例:
     1 #include <stdlib.h>  
     2 #include <stdio.h>  
     3 #include <pthread.h>  
     4   
     5 void cleanup(void *arg)  
     6 {  
     7     printf("cleanup: %s
    ", (char *)arg);  
     8 }  
     9   
    10 void *thr_fn1(void *arg)  
    11 {  
    12     printf("thread 1 start
    ");  
    13     pthread_cleanup_push(cleanup, "thread 1 first handler");  
    14     pthread_cleanup_push(cleanup, "thread 1 second handler");  
    15     printf("thread 1 push complete
    ");  
    16     if (arg)  
    17         return((void *)1);  
    18         // pthread_exit((void *)2);  
    19           
    20     pthread_cleanup_pop(0);  
    21     pthread_cleanup_pop(0);  
    22     // return((void *)1);  
    23     pthread_exit((void *)2);  
    24   
    25 }  
    26   
    27 void *thr_fn2(void *arg)  
    28 {  
    29     printf("thread 2 start
    ");  
    30     pthread_cleanup_push(cleanup, "thread 2 first handler");  
    31     pthread_cleanup_push(cleanup, "thread 2 second handler");  
    32     printf("thread 2 push complete
    ");  
    33     if (arg)  
    34         pthread_exit((void *)2);  
    35     pthread_cleanup_pop(0);  
    36     pthread_cleanup_pop(0);  
    37     pthread_exit((void *)2);  
    38 }  
    39   
    40 int main(void)  
    41 {  
    42     int         err;  
    43     pthread_t   tid1, tid2;  
    44     void        *tret;  
    45   
    46     err = pthread_create(&tid1, NULL, thr_fn1, (void *)1);  
    47     if (err != 0)  
    48         printf("can't create thread 1: %c
    ", strerror(err));  
    49     err = pthread_create(&tid2, NULL, thr_fn2, (void *)1);  
    50     if (err != 0)  
    51         printf("can't create thread 2: %c
    ", strerror(err));  
    52     err = pthread_join(tid1, &tret);  
    53     if (err != 0)  
    54         printf("can't join with thread 1: %c
    ", strerror(err));  
    55     printf("thread 1 exit code %d
    ", (int)tret);  
    56     err = pthread_join(tid2, &tret);  
    57     if (err != 0)  
    58         printf("can't join with thread 2: %c
    ", strerror(err));  
    59     printf("thread 2 exit code %d
    ", (int)tret);  
    60     exit(0);  
    61 }  
  • 相关阅读:
    创建vue项目的时候报错,spawn yarn ENOENT
    理解比特币(4)——实现原理
    比特币(3)——比特币的其他优势
    比特币(2)——最大优势是价值存储
    如何在K8S中优雅的使用私有镜像库 (Docker版)
    [Go] godoc 打开本地文档, windows 同样适用
    [FAQ] Golang error strings should not be capitalized or end with punctuation
    [Go] gorm 错误处理 与 链式/Finisher方法
    [Go] golang 替换组件包 更新 go.mod, go.sum 的方式
    [FAQ] golang-migrate/migrate error: migration failed in line 0: (details: Error 1065: Query was empty)
  • 原文地址:https://www.cnblogs.com/jikexianfeng/p/5734855.html
Copyright © 2020-2023  润新知