POSIX多线程入门学习笔记

来源:互联网 发布:淘宝会员店加盟费多少 编辑:程序博客网 时间:2024/06/02 05:31

 

一直感觉自己在做的东西,需要学习多线程编程。

今天看到http://www.kissuki.com/page/4/推荐的文章,索性进行了下学习。

POSIX(可移植操作系统接口)线程是提高代码响应和性能的有力手段。

POSIX是可移植的 多线程代码。

===============================

这个是thread1.c

 

 

root@ubuntu:/home/zhangbin/code# cd thread

root@ubuntu:/home/zhangbin/code/thread# ls

thread1.c

root@ubuntu:/home/zhangbin/code/thread# vi thread1.c

root@ubuntu:/home/zhangbin/code/thread# gcc thread1.c -o thread1 -lpthread

thread1.c: In function ‘thread_function’:

thread1.c:7: warning: incompatible implicit declaration of built-in function ‘printf’

thread1.c: In function ‘main’:

thread1.c:19: warning: incompatible implicit declaration of built-in function ‘printf’

 

===========================

没有写引用printf的头文件include <stdio.h>
exit(0)在stdlib中。
====================
运行结果
root@ubuntu:/home/zhangbin/code/thread# ls
thread1  thread1.c
root@ubuntu:/home/zhangbin/code/thread# ./thread1
thread says hi !
thread says hi !
thread says hi !
thread says hi !
thread says hi !
thread says hi !
thread says hi !
thread says hi !
thread says hi !
thread says hi !
打印了20个这句话。
=======================
void * 的返回值只是NULL么?(本程序返回的是NULL)
不是,void * 代表的是任意类型。
作者说:
 void *thread_function(void *arg)函数,
注意 thread_function() 接受 void * 作为参数,同时返回值的类型也是 void *。这表明可以用 void * 向新线程传递任意类型的数据,新线程完成时也可返回任意类型的数据
作者的意思是 void * 代表的是任意类型。
作者说:
由于我们不必理会 thread_function() 的返回值,所以将其设为 NULL.
=============pthread_create() =========
作者的讲解:
(1)pthread_t 类型在 pthread.h 中定义,通常称为“线程 id”(缩写为 "tid")。可以认为它是一种线程句柄。
 (2)pthread_create() 执行成功时返回零而失败时则返回非零值,将 pthread_create() 函数调用放在 if() 语句中只是为了方便地检测失败的调用。
===========================
函数声明参考这里http://hi.baidu.com/jrckkyy/blog/item/f3427f11a1834517b9127b97.html
#include <pthread.h>

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

Returns: 0 if OK, error number on failure

C99 中新增加了 restrict 修饰的指针: 由 restrict 修饰的指针是最初唯一对指针所指向的对象进行存取的方法,仅当第二个指针基于第一个时,才能对对象进行存取。对对象的存取都限定于基于由 restrict 修饰的指针表达式中。 由 restrict 修饰的指针主要用于函数形参,或指向由 malloc() 分配的内存空间。restrict 数据类型不改变程序的语义。 编译器能通过作出 restrict 修饰的指针是存取对象的唯一方法的假设,更好地优化某些类型的例程。

第一个参数为指向线程标识符的指针。
第二个参数用来设置线程属性。
第三个参数是线程运行函数的起始地址。
最后一个参数是运行函数的参数。

======================
第一个参数 &mythread 是指向 mythread 的指针。第二个参数当前为 NULL,可用来定义线程的某些属性。由于缺省的线程属性是适用的,只需将该参数设为 NULL。
第三个参数是新线程启动时调用的函数名。
(3)那如何向线程传递一个任意参数?很简单。只要利用 pthread_create() 中的第四个参数。本例中,因为没有必要将任何数据传给微不足道的 thread_function(),所以将第四个参数设为 NULL。
=============================
(4)可以这样理解:如果编写的程序根本没有使用 POSIX 线程,则该程序是单线程的(这个单线程称为“主”线程)。创建一个新线程之后程序总共就有两个线程了。
(5)
第一个问题,新线程创建之后主线程如何运行。答案,主线程按顺序继续执行下一行程序(本例中执行 "if (pthread_join(...))")。
第二个问题,新线程结束时如何处理。答案,新线程先停止,然后作为其清理过程的一部分,等待与另一个线程合并或“连接”。
===========pthread_join() ============================================
正如 pthread_create() 将一个线程拆分为两个, pthread_join() 将两个线程合并为一个线程。
pthread_join() 的第一个参数是 tid mythread。第二个参数是指向 void 指针的指针
如果 void 指针不为 NULL,pthread_join 将线程的 void * 返回值放置在指定的位置上。由于我们不必理会 thread_function() 的返回值,所以将其设为 NULL.
============== thread_function()和 pthread_join()的调用================
您会注意到 thread_function() 花了 20 秒才完成。
在 thread_function() 结束很久之前,主线程就已经调用了 pthread_join()。如果发生这种情况,主线程将中断(转向睡眠)然后等待 thread_function() 完成。
当 thread_function() 完成后, pthread_join() 将返回。这时程序又只有一个主线程。当程序退出时,所有新线程已经使用 pthread_join() 合并了。这就是应该如何处理在程序中创建的每个新线程的过程。如果没有合并一个新线程,则它仍然对系统的最大线程数限制不利。这意味着如果未对线程做正确的清理,最终会导致 pthread_create() 调用失败。

============================================================

如果使用过 fork() 系统调用,可能熟悉父进程和子进程的概念。当用 fork() 创建另一个新进程时,新进程是子进程,原始进程是父进程。这创建了可能非常有用的层次关系,尤其是等待子进程终止时。例如,waitpid() 函数让当前进程等待所有子进程终止。waitpid() 用来在父进程中实现简单的清理过程。

而 POSIX 线程就更有意思。您可能已经注意到我一直有意避免使用“父线程”和“子线程”的说法。这是因为 POSIX 线程中不存在这种层次关系。虽然主线程可以创建一个新线程,新线程可以创建另一个新线程,POSIX 线程标准将它们视为等同的层次。所以等待子线程退出的概念在这里没有意义。POSIX 线程标准不记录任何“家族”信息。缺少家族信息有一个主要含意:如果要等待一个线程终止,就必须将线程的 tid 传递给 pthread_join()。线程库无法为您断定 tid。

======线程清理===

对大多数开发者来说这不是个好消息,因为这会使有多个线程的程序复杂化。不过不要为此担忧。POSIX 线程标准提供了有效地管理多个线程所需要的所有工具。实际上,没有父/子关系这一事实却为在程序中使用线程开辟了更创造性的方法。例如,如果有一个线程称为线程1,线程 1 创建了称为线程 2 的线程,则线程 1 自己没有必要调用 pthread_join() 来合并线程 2,程序中其它任一线程都可以做到。当编写大量使用线程的代码时,这就可能允许发生有趣的事情。例如,可以创建一个包含所有已停止线程的全局“死线程列表”,然后让一个专门的清理线程专等停止的线程加到列表中。这个清理线程调用 pthread_join() 将刚停止的线程与自己合并。现在,仅用一个线程就巧妙和有效地处理了全部清理。

===============================================================
编写thread2.c的时候,我pthread_create(&mythread,NULL,thread_funciton,NULL))的pthread_create()字母打错了。结果thread_function()就没被系统知道。

报错如下:

 

root@ubuntu:/home/zhangbin/code/thread# gcc thread2.c -o thread2 -lpthread

thread2.c: In function ‘main’:

thread2.c:22: error: ‘thread_funciton’ undeclared (first use in this function)

thread2.c:22: error: (Each undeclared identifier is reported only once

thread2.c:22: error: for each function it appears in.)