zoukankan      html  css  js  c++  java
  • 第9章 线程编程(2)_线程创建和终止

    2. 线程的创建和终止

    (1)创建函数:pthread_create

    头文件

    #include <pthread.h>

    函数

    int pthread_create(pthread_t* tidp, const pthread_attr_t* attr, void*(*start_rtn)(void*),void* arg);

    返回值

    成功返回0,否则返回错误编号

    参数

    (1)tidp:线程标识符指针

    (2)attr:线程属性指针

    (3)start_rtn:线程运行函数的起始地址

    (4)arg:传递给线程运行函数的参数

    备注

    (1)新创建线程从start_rtn函数的地址开始执行

    (2)不能保证新线程和调用线程的执行顺序。

    【编程实验】龟兔赛跑

    //pthread_race.c

    #include <pthread.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    //实例:龟兔赛跑
    //编译选项:gcc -o bin/pthread_race src/pthread_race.c -lpthread
    
    //定义线程函数的参数类型
    typedef struct
    {
        char name[20]; //线程名称
        int  time;     //休眠时间
        int  start;    //起点
        int  end;      //终点
    }RaceArg;
    
    //定义线程运行函数
    void* th_fn(void* arg)
    {
        RaceArg* ra = (RaceArg*)arg;
        int i = ra->start;
    
        for(; i<=ra->end; i++){
            printf("%s(%lx) run %d
    ", ra->name, pthread_self(), i);
     
            usleep(ra->time); //time为微秒
        }
    
        return (void*)(ra->end - ra->start); //返回跑过的路程.
        //也可以调用pthread_exit((void*)(ra-end - ra-start));来终止线程
    }
    
    int main(void)
    { 
        srand48(time(NULL)); //随机种子,对伪随机发生器drand48进行初始化
     
        int err = 0;
        pthread_t rabbit, turtle; //定义兔子和乌龟线程
      
        //要传递给线程函数的参数(drand48返回值为介于0-1之间的double型随机数)
        RaceArg r_a = {"rabbit", (int)(drand48() * 10* 1000 * 10), 20, 50};
        RaceArg t_a = {"turtle", (int)(drand48() * 10* 1000 * 10), 10, 60};
        
        //创建兔子线程(rabbit)
        if(err = pthread_create(&rabbit, NULL, th_fn, (void*)&r_a) != 0){
            perror("pthread_create error");
        }
    
        //创建乌龟线程(turtle)
        if(err = pthread_create(&turtle, NULL, th_fn, (void*)&t_a) != 0){
            perror("pthread_create error");
        }
    
        //等待rabbit线程结束
        int* ret = NULL;
        pthread_join(rabbit, (void**)&ret);  //pthread_join(rabbit, NULL);不关心子线程返回值
        printf("rabbit's distance is %d
    ",(int)ret);
        
        //等待turtle线程结束
        pthread_join(turtle, (void**)&ret);
        printf("turtle's distance is %d
    ", (int)ret); //pthread_join(turtle, NULL);
    
        printf("main thread id: %lx
    ", pthread_self());
        printf("main thread finished!
    ");
    
        return 0;
    }

    (2)线程的终止

      ①主动终止:线程的执行函数中调用return语句或pthread_exit()

      ②被动终止:线程可以被同一进程的其它线程取消(调用pthread_cancel(pthid))。

      ③终止相关的函数

    头文件

    #include <pthread.h>

    函数

    int pthread_cancel(pthread_t tid); //终止tid线程,tid被动终止

    int pthread_exit(void* retval); //主动终止

    int pthread_join(pthread_t th, void** thread_return);//等待线程结束

    返回值

    成功返回0,否则返回错误编号

    参数

    (1)tid:要终止的线程标识符

    (2)retval:pthread_exit调用者线程的返回值,可由其他函数和pthread_join来检测获取。

    (3)th:pthread_join等待的子线程标识符。

    (4)thread_return:用户自定义指针,用来存储被等待线程的返回值。

    备注

    (1)pthread_cancel:线程可以被同一进程的其他进程取消。

    (2)由于一个进程中的多个线程共享数据段,因此通常在线程退出后,退出线程所占用的资源并不会随线程的结束而释放,所以需要调用pthread_join函数来等待线程结束,类似于wait系统调用。

    【编程实验】线程的终止

    //pthread_term.c

    #include <pthread.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    /*获取线程终止的返回值*/
    
    //定义线程函数的参数
    typedef struct
    {
        int data1;
        int data2;
    }Arg;
    
    //定义线程函数
    void* th_fn(void* arg)
    {
        Arg* ret = (Arg*)arg;
        //return (void*)(r->data1 + r->data2);
        return ret;
    }
    
    int main()
    {
        int err = 0;
        pthread_t th;
        Arg r = {20, 50};
    
        //创建新线程
        if((err = pthread_create(&th, NULL, th_fn, (void*)&r)) != 0){
            perror("pthread_create error");
        }
    
    /*
        //获取子线程的返回值
        int* result = NULL; //因为子线程的返回值是void*,当传入pthread_join后
                            //result本身会被改为子线程返回的值,而不在是NULL。
                            //这也是传入二级指针的目的,改变result本身的值。
        pthread_join(th, (void**)&result);
        printf("result is %d
    ", (int)result);
    */
    
        //获取子线程的返回值
        Arg* result = NULL;
        pthread_join(th, (void*)&result);
        printf("result is %d
    ", result->data1 + result->data2);
    
        return 0;
    }
  • 相关阅读:
    keyset与entryset
    solr4.9r+ Eclipse 4.3+ tomcat 7.5 +winds7(二)
    如何解决This system is not registered with RHN.
    堆和栈的差别(转过无数次的文章)
    墨菲定律、二八法则、马太效应、手表定理、“不值得”定律、彼得原理、零和游戏、华盛顿合作规律、酒与污水定律、水桶定律、蘑菇管理原理、钱的问题、奥卡姆剃刀等13条是左右人生的金科玉律
    atitit.软件开发GUI 布局管理优缺点总结java swing wpf web html c++ qt php asp.net winform
    漫谈并发编程(二):java线程的创建与基本控制
    exosip
    PostgreSQL服务端监听设置及client连接方法
    APK反编译。
  • 原文地址:https://www.cnblogs.com/5iedu/p/6413719.html
Copyright © 2011-2022 走看看