第十二章 POSIX 线程(一)

        在一个程序中的多个执行线路就叫做线程(thread)。更准确的定义是:线程是一个进程内部的一个控制序列。

        线程有一套完整的与其相关的函数库调用,它们中的绝大多数函数名都是以 pthread_ 开头,为了使用这些函数库调用,我们必须定义宏 _PEENTRANT,在程序中包含头文

件 pthread.h ,并且在编译程序的时需要用选项 -lpthread 来链接线程库。

pthread_create

         它的作用是创建一个新线程,类似于创建新进程的 fork 函数。它的定义如下:

       #include <pthread.h>
       int pthread_create ( pthread_t *thread, pthread_attr_t *attr, void* ( *start_routine ) ( void * ), void *arg );

       第一个参数是指向 pthread_t 类型数据的指针。线程被创建时,这个指针指向的变量中将被写入一个标识符,我们用该标识符来引用新线程。下一个参数用于设置线程的属性。我们一般不需要特殊的属性,所以只需设置该参数为 NULL。最后两个参数分别告诉线程将要启动执行的函数和传递给该函数的参数。

       void * ( *start_routine ) ( void * )

      上面一行告诉我们必须要传递一个函数地址,该函数以一个指向 void 的指针为参数,返回的也是一个指向 void 的指针。因此,可以传递一个任一类型的参数并返回一个任一类型的指针。用 fork 调用后,父进程将在同一位置继续执行下去,只是 fork 调用的返回值是不同的;但对新线程来说,我们必须明确地提供给它一个函数指针,新线程将在这个新位置开始执行。

       该函数调用成功时返回值是 0,如果失败则返回错误代码。

       线程通过调用 pthread_exit 函数终止执行,就如同进程在结束时调用 exit 函数一样。这个函数的作用是,终止调用它的线程并返回一个指向某个对象的指针。注意,绝不能用它来返回一个指向局部变量的指针,因为线程调用该函数后,这个局部变量就不再存在了,这将引起严重的程序漏洞。

pthread_exit 函数定义如下:
#include <pthread.h>
void pthread_exit ( void *retval );

       pthread_join 函数在线程中的作用等价于进程中用来搜集子进程信息的 wait 函数。这个函数的定义如下:
#include <pthread.h>
int pthread_join ( pthread_t th, void **thread_return );
       第一个参数指定了将要等待的线程,线程通过 pthread_create 返回的标识符来指定。第二个参数是一个指针,它指向另一个指针,而后者指向线程的返回值。与 pthread_create 类似,这个函数在成功时返回0,失败时返回错误代码。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

void *thread_function(void *arg);

char message[] = "Hello World";

int main() {
    int res;
    pthread_t a_thread;
    void *thread_result;
    res = pthread_create(&a_thread, NULL, thread_function, (void *)message);
    if (res != 0) {
        perror("Thread creation failed");
        exit(EXIT_FAILURE);
    }
    printf("Waiting for thread to finish...\n");
    res = pthread_join(a_thread, &thread_result);
    if (res != 0) {
        perror("Thread join failed");
        exit(EXIT_FAILURE);
    }
    printf("Thread joined, it returned %s\n", (char *)thread_result);
    printf("Message is now %s\n", message);
    exit(EXIT_SUCCESS);
}

void *thread_function(void *arg) {
    printf("thread_function is running. Argument was %s\n", (char *)arg);
    sleep(3);
    strcpy(message, "Bye!");
    pthread_exit("Thank you for the CPU time");
}
$ ./thread1
Waiting for thread to finish...
thread_function is running. Argument was Hello World
Thread joined, it returned Thank you for the CPU time
Message is now Bye!

实验解析

       首先,我们定义了在创建线程时需要由它调用的一个函数原型。如下所示:

       void *thread_function ( void *arg );

       根据 pthread_create 的要求,它只有一个指向 void 的指针作为参数,返回的也是指向 void 的指针。稍后,将介绍这个函数的实现。

       在 main 函数中,我们首先定义了几个变量,然后调用 pthread_create 开始运行新线程。如下所示:

       pthread_t a_thread;
       void *thread_result;
       res = pthread_create(&a_thread, NULL, thread_function, (void *)message);
      我们向 pthread_create 函数传递了一个 pthread_t 类型对象的地址,今后可以用它来引用这个新线程。我们不想改变默认的线程属性,所以设第二个参数为 NULL。最后两个参数分别为将要调用的函数和一个传递给该函数的参数。
       如果这个调用成功了,就会有两个线程在运行。原先的线程(main)继续执行 pthread_create 后面的代码,而新线程开始执行 thread_function 函数。
       原先的线程在查明新线程已经启动后,将调用 pthread_join 函数。如下所示:
       res = pthread_join ( a_thread, &thread_result );
       我们给干旱数传递两个参数,一个是正在等待其结束的线程的标识符,另一个是指向线程返回值的指针。这个函数将等到它所指定的线程终止后才返回。然后主线程将打印新线程的返回值和全局变量 message 的值,然后退出。
       新线程在 thread_function 函数中开始执行,它先打印出自己的参数,休眠一会儿,然后更新全局变量,最后退出并向主线程返回一个字符串。新线程修改了数组 message。而原先的线程也可以访问该数组。如果我们调用的是 fork 而不是 pthread_create ,就不会有这样的效果。

同时执行(轮询技术)

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>

void *thread_function(void *arg);
int run_now = 1;
char message[] = "Hello World";

int main() {
    int res;
    pthread_t a_thread;
    void *thread_result;
    int print_count1 = 0;

    res = pthread_create(&a_thread, NULL, thread_function, (void *)message);
    if (res != 0) {
        perror("Thread creation failed");
        exit(EXIT_FAILURE);
    }

    while(print_count1++ < 20) {
        if (run_now == 1) {
            printf("1");
            run_now = 2;
        }
        else {
            sleep(1);
        }
    }

    printf("\nWaiting for thread to finish...\n");
    res = pthread_join(a_thread, &thread_result);
    if (res != 0) {
        perror("Thread join failed");
        exit(EXIT_FAILURE);
    }
    printf("Thread joined\n");
    exit(EXIT_SUCCESS);
}

void *thread_function(void *arg) {
    int print_count2 = 0;

    while(print_count2++ < 20) {
        if (run_now == 2) {
            printf("2");
            run_now = 1;
        }
        else {
            sleep(1);
        }
    }

    sleep(3);
}

$ cc -D_REENTRANT thread3.c -o thread2 -lpthread
$ ./thread2
12121212121212121212
Waiting for thread to finish...
Thread joined


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值