Chapter11 线程

1. void 和void* 的使用

    void 意思是无类型,void* 意思是无类型指针,可以指向所有数据类型。

    (1) void 主要用于对函数参数和返回值的限定,加上void 限定则表明该函数不接受参数或者无返回值(因为在C语言中,即使函数声明时无参数,在函数调用时传进参数是不会报错的,即使函数没有指定返回类型,函数会默认返回int类型,所以加上void 限定是十分有必要的)

    (2) void* 则多用于函数参数(或返回值)可以是任意类型的情况下,因为void* 可以接受任意类型而无需强制装换,但将其转换为具体类型则需要强制装换,这有点类似于C++中的继承关系。

2. 线程创建与线程标识

    线程ID 用pthread_t 数据结构来表示,在不同的操作系统中表示方法不同,所以可移植的操作系统实现不能把它作为整数处理,因此必须使用 pthread_equal() (函数原型:int pthread_equal(pthread_t tid1, pthread_t tid2);)函数来对像个线程ID 进行比较。调用 pthread_self 函数可以获取自身线程ID。

    在传统Unix进程模型中,每个进程只有一个线程。在POSIX线程的情况下, 当程序开始运行时,也是以单进程中的单个控制线程启动的,并可以通过pthread_create函数创建新线程。(函数原型: int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rth)(void*), void *restrict arg);) 其中tidp为 ID,attr为订制线程属性,start_rth 是线程开始运行的函数地址,arg是该函数的参数(若由多个参数,则使用结构体)

    《APUE》 程序清单 11-1 打印线程ID:

 1 #include "apue.h"
 2 #include <pthread.h>
 3 
 4 pthread_t ntid;
 5 
 6 void printids(const char* s) {
 7     pid_t     pid;
 8     pthread_t tid;
 9 
10     pid = getpid();
11     tid = pthread_self();
12     printf("%s pid %u tid %u (0x%x)\n", s, (unsigned int)pid,
13         (unsigned int)tid, (unsigned int)tid);
14 }
15 
16 void* thr_fn(void* arg) {
17     printids("new thread: ");
18     return ((void*)0);
19 }
20 
21 int main()
22 {
23     int err;
24     err = pthread_create(&ntid, NULL, thr_fn, NULL);
25     if (err != 0)
26         err_quit("can‘t create thread: %s\n", strerror(err));
27     printids("main thread: ");
28 
29     sleep(1);
30     exit(0);
31 }

    程序运行结果:

     main thread:  pid 20961 tid 4253615936 (0xfd890740)
     new thread:  pid 20961 tid 4245337856 (0xfd0ab700)
   进程ID 相同, 线程ID 不同

3. 线程终止

    终止线程有三种方式,在不终止整个进程的情况下终止它的控制流(注意进程中任一线程调用了exit, _Exit 或者_exit ,那么整个进程就会终止)

  • 线程只是从启动历程中返回,返回值是线程的退出码 (return)
  • 线程可以被同一进程中的其他线程取消。(int pthread_cancel(phread_ tid);)
  • 线程调用pthread_exit. (函数原型: void pthread_exit(void *rval_ptr);  )

    有时程序要了保证在主进程结束前线程运行结束,会在主进程中调用sleep。也可以使用pthread_join (函数原型: int pthread_join(pthread_t thread, void** rval_ptr);  )

    函数,调用该函数时,调用线程会一直阻塞,直到指定的线程调用pthread_exit,从启动例程中返回或者别取消。另外通过pthread_join函数还可以访问到 pthread_exit()

    参数中的rval_ptr 指针。

 

3. 线程清理处理程序(thread cleanup handler)

    线程可以安排它退出时需要调用的函数,这些处理程序记录在栈中,可以使用pthread_cleanup_push() 函数注册多个清理处理程序。

    在下面三种情况下,已经注册的清理处理程序将会被调用

  •     调用pthread_exit时 (注意return时不会调用)
  •     相应取消请求时
  •     用非零参数调用pthread_cleanup_pop 时 (与pthread_cleanup_push相对应)

Chapter11 线程,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。