浅墨浓香

想要天亮进城,就得天黑赶路。

导航

第9章 线程编程(2)_线程创建和终止

Posted on 2017-02-18 17:48  浅墨浓香  阅读(348)  评论(0编辑  收藏  举报

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\n", 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\n",(int)ret);
    
    //等待turtle线程结束
    pthread_join(turtle, (void**)&ret);
    printf("turtle's distance is %d\n", (int)ret); //pthread_join(turtle, NULL);

    printf("main thread id: %lx\n", pthread_self());
    printf("main thread finished!\n");

    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\n", (int)result);
*/

    //获取子线程的返回值
    Arg* result = NULL;
    pthread_join(th, (void*)&result);
    printf("result is %d\n", result->data1 + result->data2);

    return 0;
}