📄 posix 线程详解1.htm
字号:
<TD><IMG height=16 alt=""
src="POSIX 线程详解1.files/fw_bold.gif" width=16
vspace=3 border=0></TD>
<TD width=125>
<P><A class=smallplainlink
href="http://www-128.ibm.com/developerworks/cn/kickstart/">Java
应用开发源动力 - 下载免费软件,快速启动开发</A>
</P></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><!--END RESERVED FOR FUTURE USE INCLUDE FILES--><BR></TD></TR></TBODY></TABLE>
<P>级别: 初级</P>
<P><A
href="http://www-128.ibm.com/developerworks/cn/linux/thread/posix_thread1/index.html#author">Daniel
Robbins</A>, 总裁/CEO, Gentoo Technologies, Inc.<BR></P>
<P>2000 年 7 月 01 日</P>
<BLOCKQUOTE>POSIX(可移植操作系统接口)线程是提高代码响应和性能的有力手段。在本系列中,Daniel Robbins
向您精确地展示在编程中如何使用线程。其中还涉及大量幕后细节,读完本系列文章,您完全可以运用 POSIX
线程创建多线程程序。</BLOCKQUOTE><!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
<P><A name=N10046><SPAN class=atitle>线程是有趣的</SPAN></A></P>
<P>了解如何正确运用线程是每一个优秀程序员必备的素质。线程类似于进程。如同进程,线程由内核按时间分片进行管理。在单处理器系统中,内核使用时间分片来模拟线程的并发执行,这种方式和进程的相同。而在多处理器系统中,如同多个进程,线程实际上一样可以并发执行。</P>
<P>那么为什么对于大多数合作性任务,多线程比多个独立的进程更优越呢?这是因为,线程共享相同的内存空间。不同的线程可以存取内存中的同一个变量。所以,程序中的所有线程都可以读或写声明过的全局变量。如果曾用
fork() 编写过重要代码,就会认识到这个工具的重要性。为什么呢?虽然 fork() 允许创建多个进程,但它还会带来以下通信问题:
如何让多个进程相互通信,这里每个进程都有各自独立的内存空间。对这个问题没有一个简单的答案。虽然有许多不同种类的本地 IPC
(进程间通信),但它们都遇到两个重要障碍:</P>
<UL>
<LI>强加了某种形式的额外内核开销,从而降低性能。
<LI>对于大多数情形,IPC 不是对于代码的“自然”扩展。通常极大地增加了程序的复杂性。 </LI></UL>
<P>双重坏事: 开销和复杂性都非好事。如果曾经为了支持 IPC
而对程序大动干戈过,那么您就会真正欣赏线程提供的简单共享内存机制。由于所有的线程都驻留在同一内存空间,POSIX
线程无需进行开销大而复杂的长距离调用。只要利用简单的同步机制,程序中所有的线程都可以读取和修改已有的数据结构。而无需将数据经由文件描述符转储或挤入紧窄的共享内存空间。仅此一个原因,就足以让您考虑应该采用单进程/多线程模式而非多进程/单线程模式。</P><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD><IMG height=1 alt="" src="POSIX 线程详解1.files/blue_rule.gif"
width="100%"><BR><IMG height=6 alt=""
src="POSIX 线程详解1.files/c.gif" width=8
border=0></TD></TR></TBODY></TABLE>
<TABLE class=no-print cellSpacing=0 cellPadding=0 align=right>
<TBODY>
<TR align=right>
<TD><IMG height=4 alt="" src="POSIX 线程详解1.files/c.gif"
width="100%"><BR>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt=""
src="POSIX 线程详解1.files/u_bold.gif" width=16
border=0><BR></TD>
<TD vAlign=top align=right><A class=fbox
href="http://www-128.ibm.com/developerworks/cn/linux/thread/posix_thread1/index.html#main"><B>回页首</B></A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR>
<P><A name=N1005E><SPAN class=atitle>线程是快捷的</SPAN></A></P>
<P>不仅如此。线程同样还是非常快捷的。与标准 fork()
相比,线程带来的开销很小。内核无需单独复制进程的内存空间或文件描述符等等。这就节省了大量的 CPU
时间,使得线程创建比新进程创建快上十到一百倍。因为这一点,可以大量使用线程而无需太过于担心带来的 CPU 或内存不足。使用 fork()
时导致的大量 CPU 占用也不复存在。这表示只要在程序中有意义,通常就可以创建线程。</P>
<P>当然,和进程一样,线程将利用多
CPU。如果软件是针对多处理器系统设计的,这就真的是一大特性(如果软件是开放源码,则最终可能在不少平台上运行)。特定类型线程程序(尤其是
CPU 密集型程序)的性能将随系统中处理器的数目几乎线性地提高。如果正在编写 CPU
非常密集型的程序,则绝对想设法在代码中使用多线程。一旦掌握了线程编码,无需使用繁琐的 IPC
和其它复杂的通信机制,就能够以全新和创造性的方法解决编码难题。所有这些特性配合在一起使得多线程编程更有趣、快速和灵活。</P><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD><IMG height=1 alt="" src="POSIX 线程详解1.files/blue_rule.gif"
width="100%"><BR><IMG height=6 alt=""
src="POSIX 线程详解1.files/c.gif" width=8
border=0></TD></TR></TBODY></TABLE>
<TABLE class=no-print cellSpacing=0 cellPadding=0 align=right>
<TBODY>
<TR align=right>
<TD><IMG height=4 alt="" src="POSIX 线程详解1.files/c.gif"
width="100%"><BR>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt=""
src="POSIX 线程详解1.files/u_bold.gif" width=16
border=0><BR></TD>
<TD vAlign=top align=right><A class=fbox
href="http://www-128.ibm.com/developerworks/cn/linux/thread/posix_thread1/index.html#main"><B>回页首</B></A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR>
<P><A name=N1006A><SPAN class=atitle>线程是可移植的</SPAN></A></P>
<P>如果熟悉 Linux 编程,就有可能知道 __clone() 系统调用。__clone() 类似于
fork(),同时也有许多线程的特性。例如,使用
__clone(),新的子进程可以有选择地共享父进程的执行环境(内存空间,文件描述符等)。这是好的一面。但 __clone()
也有不足之处。正如__clone() 在线帮助指出:</P>
<BLOCKQUOTE>“__clone 调用是特定于 Linux
平台的,不适用于实现可移植的程序。欲编写线程化应用程序(多线程控制同一内存空间),最好使用实现 POSIX 1003.1c 线程
API 的库,例如 Linux-Threads 库。参阅 pthread_create(3thr)。” </BLOCKQUOTE>
<P>虽然 __clone() 有线程的许多特性,但它是不可移植的。当然这并不意味着代码中不能使用它。但在软件中考虑使用
__clone() 时应当权衡这一事实。值得庆幸的是,正如 __clone() 在线帮助指出,有一种更好的替代方案:POSIX
线程。如果想编写 <B>可移植的</B> 多线程代码,代码可运行于 Solaris、FreeBSD、Linux 和其它平台,POSIX
线程是一种当然之选。 </P><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD><IMG height=1 alt="" src="POSIX 线程详解1.files/blue_rule.gif"
width="100%"><BR><IMG height=6 alt=""
src="POSIX 线程详解1.files/c.gif" width=8
border=0></TD></TR></TBODY></TABLE>
<TABLE class=no-print cellSpacing=0 cellPadding=0 align=right>
<TBODY>
<TR align=right>
<TD><IMG height=4 alt="" src="POSIX 线程详解1.files/c.gif"
width="100%"><BR>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt=""
src="POSIX 线程详解1.files/u_bold.gif" width=16
border=0><BR></TD>
<TD vAlign=top align=right><A class=fbox
href="http://www-128.ibm.com/developerworks/cn/linux/thread/posix_thread1/index.html#main"><B>回页首</B></A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR>
<P><A name=N1007C><SPAN class=atitle>第一个线程</SPAN></A></P>
<P>下面是一个 POSIX 线程的简单示例程序:</P><BR><A
name=N10085><B>thread1.c</B></A><BR>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee
border=1>
<TBODY>
<TR>
<TD><PRE><CODE class=section>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
void *thread_function(void *arg) {
int i;
for ( i=0; i<20; i++) {
printf("Thread says hi!\n");
sleep(1);
}
return NULL;
}
int main(void) {
pthread_t mythread;
if ( pthread_create( &mythread, NULL, thread_function, NULL) ) {
printf("error creating thread.");
abort();
}
if ( pthread_join ( mythread, NULL ) ) {
printf("error joining thread.");
abort();
}
exit(0);
}
</CODE></PRE></TD></TR></TBODY></TABLE><BR>
<P>要编译这个程序,只需先将程序存为 thread1.c,然后输入:</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee
border=1>
<TBODY>
<TR>
<TD><PRE><CODE class=section>
$ gcc thread1.c -o thread1 -lpthread
</CODE></PRE></TD></TR></TBODY></TABLE><BR>
<P>运行则输入:</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee
border=1>
<TBODY>
<TR>
<TD><PRE><CODE class=section>
$ ./thread1
</CODE></PRE></TD></TR></TBODY></TABLE><BR><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD><IMG height=1 alt="" src="POSIX 线程详解1.files/blue_rule.gif"
width="100%"><BR><IMG height=6 alt=""
src="POSIX 线程详解1.files/c.gif" width=8
border=0></TD></TR></TBODY></TABLE>
<TABLE class=no-print cellSpacing=0 cellPadding=0 align=right>
<TBODY>
<TR align=right>
<TD><IMG height=4 alt="" src="POSIX 线程详解1.files/c.gif"
width="100%"><BR>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt=""
src="POSIX 线程详解1.files/u_bold.gif" width=16
border=0><BR></TD>
<TD vAlign=top align=right><A class=fbox
href="http://www-128.ibm.com/developerworks/cn/linux/thread/posix_thread1/index.html#main"><B>回页首</B></A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR>
<P><A name=N1009D><SPAN class=atitle>理解 thread1.c</SPAN></A></P>
<P>thread1.c
是一个非常简单的线程程序。虽然它没有实现什么有用的功能,但可以帮助理解线程的运行机制。下面,我们一步一步地了解这个程序是干什么的。main()
中声明了变量 mythread,类型是 pthread_t。pthread_t 类型在 pthread.h 中定义,通常称为“线程
id”(缩写为 "tid")。可以认为它是一种线程句柄。</P>
<P>mythread 声明后(记住 mythread 只是一个 "tid",或是将要创建的线程的句柄),调用
pthread_create 函数创建一个真实活动的线程。不要因为 pthread_create() 在 "if"
语句内而受其迷惑。由于 pthread_create() 执行成功时返回零而失败时则返回非零值,将 pthread_create()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -