pthreads —— POSIX线程 7

原文:http://www.cnblogs.com/huyc/archive/2011/10/21/2219758.html


NAME

       pthreads —— POSIX线程

DESCRIPTION
POSIX.1指定了一个接口集(函数,头文件)用于线程化编程俗称POSIX线程。单个进程可以包含多个线程,所有的线程都在一个程序中执行。这些线程共享一样的全局内存(数据段和堆段),但是每个线程有自己的堆栈(自动分配)
POSIX.1要求给出线程属性的共享范围(这些属性是全局进程的而非线程私有的):
-  进程ID
-  父进程ID
-  进程组ID和会话ID
-  控制终端
-  用户和组ID
-  打开的文件描述符
-  记录锁(参见fcntl(2))
-  信号处理函数
-  文件模式掩码(umask(2))
-  当前目录(chdir(2))和根目录(chroot(2))
-  脉冲定时器(setitimer(2))和POSIX定时器(timer_create(2))
-  nice值(setpriority(2))
-  资源限制(setrlimit(2))
-  消耗的CPU时间(times(2))和资源(getrusage(2))量度值。
跟堆栈一样,POSIX.1指定了各种其它线程各不相同的属性,包括:
-  线程ID(pthread_t数据类型)
-  信号掩码(pthread_sigmask(3))
-  errno变量
-  独立的信号栈(sigaltstack(2))
-  实时调度策略和优先级(sched_setscheduler(2)和sched_setparam(2))
下面的Linux特有特性也对每个线程有效:
-  特权(参见capabilities(7))
-  CPU亲和力(sched_setaffinity(2))
线程函数的返回值
绝大多数POSIX线程函数返回0表示成功,返回错误值指示失败。POSIX线程并不设置errno。每个线程函数可以直接返回错误值,POSIX.1-2001指定这些函数失败时从不返回EINTR。
线程ID
进程中的每个线程都有一个唯一的线程标识(保存类型为pthread_t)。这个标识是调用pthread_create返回的,线程也可以调用pthread_self获得自己的线程标识。线程ID只保证在进程内唯一。一个进程内的线程ID可以在终止的线程被join后重用,或者在分离线程终止后重用。所有的线程函数接受一个线程ID作为参数,此ID引用到该进程中的一个线程。
线程安全的函数
一个线程安全的函数是一个可以安全地(亦即,不论如何都会提供相同的结果)同时被多个线程调用的函数。
POSIX.1-2001和POSIX.1-2008要求标准指定的所有函数都应该是线程安全的,除了以下函数:
View Code
 1 asctime()
 2 basename()
 3 catgets()
 4 crypt()
 5 ctermid() if passed a non-NULL argument
 6 ctime()
 7 dbm_clearerr()
 8 dbm_close()
 9 dbm_delete()
10 dbm_error()
11 dbm_fetch()
12 dbm_firstkey()
13 dbm_nextkey()
14 dbm_open()
15 dbm_store()
16 dirname()
17 dlerror()
18 drand48()
19 ecvt() [POSIX.1-2001 only (function removed in POSIX.1-2008)]
20 encrypt()
21 endgrent()
22 endpwent()
23 endutxent()
24 fcvt() [POSIX.1-2001 only (function removed in POSIX.1-2008)]
25 ftw()
26 gcvt() [POSIX.1-2001 only (function removed in POSIX.1-2008)]
27 getc_unlocked()
28 getchar_unlocked()
29 getdate()
30 getenv()
31 getgrent()
32 getgrgid()
33 getgrnam()
34 gethostbyaddr() [POSIX.1-2001 only (function removed in POSIX.1-2008)]
35 gethostbyname() [POSIX.1-2001 only (function removed in POSIX.1-2008)]
36 gethostent()
37 getlogin()
38 getnetbyaddr()
39 getnetbyname()
40 getnetent()
41 getopt()
42 getprotobyname()
43 getprotobynumber()
44 getprotoent()
45 getpwent()
46 getpwnam()
47 getpwuid()
48 getservbyname()
49 getservbyport()
50 getservent()
51 getutxent()
52 getutxid()
53 getutxline()
54 gmtime()
55 hcreate()
56 hdestroy()
57 hsearch()
58 inet_ntoa()
59 l64a()
60 lgamma()
61 lgammaf()
62 lgammal()
63 localeconv()
64 localtime()
65 lrand48()
66 mrand48()
67 nftw()
68 nl_langinfo()
69 ptsname()
70 putc_unlocked()
71 putchar_unlocked()
72 putenv()
73 pututxline()
74 rand()
75 readdir()
76 setenv()
77 setgrent()
78 setkey()
79 setpwent()
80 setutxent()
81 strerror()
82 strsignal() [Added in POSIX.1-2008]
83 strtok()
84 system() [Added in POSIX.1-2008]
85 tmpnam() if passed a non-NULL argument
86 ttyname()
87 unsetenv()
88 wcrtomb() if its final argument is NULL
89 wcsrtombs() if its final argument is NULL
90 wcstombs()
91 wctomb()
取消点
POSIX.1指定某些函数必须,另外某些函数可以,成为取消点。如果一个线程是可取消的,其取消的属性是延时的,如果它有一个取消请求是未决的,则线程执行到取消点函数时取消。
下面的函数在POSIX.1-2001和/或POSIX.1-2008中要求必须是一个取消点:
View Code
 1 accept()
 2 aio_suspend()
 3 clock_nanosleep()
 4 close()
 5 connect()
 6 creat()
 7 fcntl() F_SETLKW
 8 fdatasync()
 9 fsync()
10 getmsg()
11 getpmsg()
12 lockf() F_LOCK
13 mq_receive()
14 mq_send()
15 mq_timedreceive()
16 mq_timedsend()
17 msgrcv()
18 msgsnd()
19 msync()
20 nanosleep()
21 open()
22 openat() [Added in POSIX.1-2008]
23 pause()
24 poll()
25 pread()
26 pselect()
27 pthread_cond_timedwait()
28 pthread_cond_wait()
29 pthread_join()
30 pthread_testcancel()
31 putmsg()
32 putpmsg()
33 pwrite()
34 read()
35 readv()
36 recv()
37 recvfrom()
38 recvmsg()
39 select()
40 sem_timedwait()
41 sem_wait()
42 send()
43 sendmsg()
44 sendto()
45 sigpause() [POSIX.1-2001 only (moves to "may" list in POSIX.1-2008)]
46 sigsuspend()
47 sigtimedwait()
48 sigwait()
49 sigwaitinfo()
50 sleep()
51 system()
52 tcdrain()
53 usleep() [POSIX.1-2001 only (function removed in POSIX.1-2008)]
54 wait()
55 waitid()
56 waitpid()
57 write()
58 writev()
下面的函数在POSIX.1-2001和/或POSIX.1-2008中要求可以是一个取消点:
View Code
  1 access()
  2 asctime()
  3 asctime_r()
  4 catclose()
  5 catgets()
  6 catopen()
  7 chmod() [Added in POSIX.1-2008]
  8 chown() [Added in POSIX.1-2008]
  9 closedir()
 10 closelog()
 11 ctermid()
 12 ctime()
 13 ctime_r()
 14 dbm_close()
 15 dbm_delete()
 16 dbm_fetch()
 17 dbm_nextkey()
 18 dbm_open()
 19 dbm_store()
 20 dlclose()
 21 dlopen()
 22 dprintf() [Added in POSIX.1-2008]
 23 endgrent()
 24 endhostent()
 25 endnetent()
 26 endprotoent()
 27 endpwent()
 28 endservent()
 29 endutxent()
 30 faccessat() [Added in POSIX.1-2008]
 31 fchmod() [Added in POSIX.1-2008]
 32 fchmodat() [Added in POSIX.1-2008]
 33 fchown() [Added in POSIX.1-2008]
 34 fchownat() [Added in POSIX.1-2008]
 35 fclose()
 36 fcntl() (for any value of cmd argument)
 37 fflush()
 38 fgetc()
 39 fgetpos()
 40 fgets()
 41 fgetwc()
 42 fgetws()
 43 fmtmsg()
 44 fopen()
 45 fpathconf()
 46 fprintf()
 47 fputc()
 48 fputs()
 49 fputwc()
 50 fputws()
 51 fread()
 52 freopen()
 53 fscanf()
 54 fseek()
 55 fseeko()
 56 fsetpos()
 57 fstat()
 58 fstatat() [Added in POSIX.1-2008]
 59 ftell()
 60 ftello()
 61 ftw()
 62 futimens() [Added in POSIX.1-2008]
 63 fwprintf()
 64 fwrite()
 65 fwscanf()
 66 getaddrinfo()
 67 getc()
 68 getc_unlocked()
 69 getchar()
 70 getchar_unlocked()
 71 getcwd()
 72 getdate()
 73 getdelim() [Added in POSIX.1-2008]
 74 getgrent()
 75 getgrgid()
 76 getgrgid_r()
 77 getgrnam()
 78 getgrnam_r()
 79 gethostbyaddr() [SUSv3 only (function removed in POSIX.1-2008)]
 80 gethostbyname() [SUSv3 only (function removed in POSIX.1-2008)]
 81 gethostent()
 82 gethostid()
 83 gethostname()
 84 getline() [Added in POSIX.1-2008]
 85 getlogin()
 86 getlogin_r()
 87 getnameinfo()
 88 getnetbyaddr()
 89 getnetbyname()
 90 getnetent()
 91 getopt() (if opterr is non-zero)
 92 getprotobyname()
 93 getprotobynumber()
 94 getprotoent()
 95 getpwent()
 96 getpwnam()
 97 getpwnam_r()
 98 getpwuid()
 99 getpwuid_r()
100 gets()
101 getservbyname()
102 getservbyport()
103 getservent()
104 getutxent()
105 getutxid()
106 getutxline()
107 getwc()
108 getwchar()
109 getwd() [SUSv3 only (function removed in POSIX.1-2008)]
110 glob()
111 iconv_close()
112 iconv_open()
113 ioctl()
114 link()
115 linkat() [Added in POSIX.1-2008]
116 lio_listio() [Added in POSIX.1-2008]
117 localtime()
118 localtime_r()
119 lockf() [Added in POSIX.1-2008]
120 lseek()
121 lstat()
122 mkdir() [Added in POSIX.1-2008]
123 mkdirat() [Added in POSIX.1-2008]
124 mkdtemp() [Added in POSIX.1-2008]
125 mkfifo() [Added in POSIX.1-2008]
126 mkfifoat() [Added in POSIX.1-2008]
127 mknod() [Added in POSIX.1-2008]
128 mknodat() [Added in POSIX.1-2008]
129 mkstemp()
130 mktime()
131 nftw()
132 opendir()
133 openlog()
134 pathconf()
135 pclose()
136 perror()
137 popen()
138 posix_fadvise()
139 posix_fallocate()
140 posix_madvise()
141 posix_openpt()
142 posix_spawn()
143 posix_spawnp()
144 posix_trace_clear()
145 posix_trace_close()
146 posix_trace_create()
147 posix_trace_create_withlog()
148 posix_trace_eventtypelist_getnext_id()
149 posix_trace_eventtypelist_rewind()
150 posix_trace_flush()
151 posix_trace_get_attr()
152 posix_trace_get_filter()
153 posix_trace_get_status()
154 posix_trace_getnext_event()
155 posix_trace_open()
156 posix_trace_rewind()
157 posix_trace_set_filter()
158 posix_trace_shutdown()
159 posix_trace_timedgetnext_event()
160 posix_typed_mem_open()
161 printf()
162 psiginfo() [Added in POSIX.1-2008]
163 psignal() [Added in POSIX.1-2008]
164 pthread_rwlock_rdlock()
165 pthread_rwlock_timedrdlock()
166 pthread_rwlock_timedwrlock()
167 pthread_rwlock_wrlock()
168 putc()
169 putc_unlocked()
170 putchar()
171 putchar_unlocked()
172 puts()
173 pututxline()
174 putwc()
175 putwchar()
176 readdir()
177 readdir_r()
178 readlink() [Added in POSIX.1-2008]
179 readlinkat() [Added in POSIX.1-2008]
180 remove()
181 rename()
182 renameat() [Added in POSIX.1-2008]
183 rewind()
184 rewinddir()
185 scandir() [Added in POSIX.1-2008]
186 scanf()
187 seekdir()
188 semop()
189 setgrent()
190 sethostent()
191 setnetent()
192 setprotoent()
193 setpwent()
194 setservent()
195 setutxent()
196 sigpause() [Added in POSIX.1-2008]
197 stat()
198 strerror()
199 strerror_r()
200 strftime()
201 symlink()
202 symlinkat() [Added in POSIX.1-2008]
203 sync()
204 syslog()
205 tmpfile()
206 tmpnam()
207 ttyname()
208 ttyname_r()
209 tzset()
210 ungetc()
211 ungetwc()
212 unlink()
213 unlinkat() [Added in POSIX.1-2008]
214 utime() [Added in POSIX.1-2008]
215 utimensat() [Added in POSIX.1-2008]
216 utimes() [Added in POSIX.1-2008]
217 vdprintf() [Added in POSIX.1-2008]
218 vfprintf()
219 vfwprintf()
220 vprintf()
221 vwprintf()
222 wcsftime()
223 wordexp()
224 wprintf()
225 wscanf()
一个实现可以标记其它没有在标准中指定的函数成为取消点。特别的,一个实现可能将任意非标准,但可能阻塞的函数标记为一个取消点。(这包括绝大多数可以操作文件的函数)
Linux下的编译
Linux下,使用POSIX线程API的程序应该带上pthread选项:cc -pthread。
Linux的POSIX线程实现
GNU Linux下的C库提供了两个线程实现:
       Linux线程
              这个是POSIX原来的实现。glibc 2.4以来,这个实现不再被支持了。
       NPTL(本地POSIX线程库)
              这是现代POSIX线程实现。相比于Linux线程,NPTL提供最符合POSIX.1规范,创建大量线程时有更好的性能。NPTL从glibc 2.3.2可用,需要Linux 2.6内核的特性。
这是所谓的1:1实现,意味着每个线程映射到内核调度项。两个线程实现采用clone(2)系统调用。NPTL,线程同步原语(互斥锁,线程join,等等)是用futex(2)系统调用实现的。
Linux线程
这个实现的显著特点如下:
-  除了主线程和pthread_create创建的线程,这个实现创建一个管理线程。此线程负责线程创建和终止。(如果此线程意外终止可能会引发问题)
-  实现内部使用的信号。Linux 2.2往后使用了前三个实时信号(参见signal(7))。更老一些的Linux内核,使用的是SIGUSR1和SIGUSR2。应用必须避免使用任何被占用了的信号集。
-  各线程不共享进程ID。(效果上看,Linux线程是作为进程实现的,他们共享更多的信息,但不共享进程ID)Linux线程(包括管理线程)可以被作为单独进程显示,使用ps(1)。
Linux线程实现偏离了POSIX.1规范,包括以下几点:
-  在每个线程中调用getpid(2)返回不同的值。
-  主线程之外的线程调用getppid(2)返回管理线程的进程ID,这些线程应该返回同样的值,跟主线程返回的一样。
-  当一个线程用fork创建了一个新的子进程,任何线程应该都可以调用wait。然而,这个实现只允许创建该子进程的线程wait。
-  当一个线程调用execve,所有的线程都应该被终止(POSIX.1是这样要求的)。然而,新的进程拥有和调用execve的线程一样的PID:它应该跟主进程有一样的PID才对。
-  线程不共享用户和组ID。这会导致设置用户ID程序出现问题,如果一个应用使用类似于seteuid(2)改变它的凭据,这将引起线程函数失败。
-  线程不共享共同的会话ID和进程组ID。
-  线程不共享fcntl创建的记录锁。
-  times(2)和getrusage(2)返回的信息是线程私有的而非全局进程的。
-  线程不共享信号量复位值(参见semop(2))
-  线程不共享间隔定时器。
-  线程不共享共同的nice值。
-  POSIX.1区分传递给整个进程和传递给线程的信号的概念。根据POSIX.1,一个发向进程的信号(比如用kill发送)应该是进程内的一个任意选择的线程。Linux线程不支持这样的进程信号:信号只能发送到指定线程。
-  线程有互不相同的备用信号栈设置。然而,一个新线程的备用信号栈设置会从创建它的线程那拷贝过来,于是两个线程初始化为共享一个备用信号栈。(新线程启动时应该没有定义备用信号栈。如果两个线程同时在共享的备用信号栈上处理信号,奇特的事情就会发生了)
NPTL
对于NPTL,一个进程内的所有线程被放在同一线程组,所有的线程组成语共享一样的PID。NPTL没有管理线程。NPTL内部使用前两个实时信号(参见signal(7)),它们不能在应用中使用。
NPTL仍然有至少一个与POSIX.1不一致的地方:
-  线程不共享共同的nice值。
一些NPTL不一致也能出现在更老的内核:
-  times(2)和getrusage(2)的返回值是线程局部而非进程全局的(fixed in kernel 2.6.9)。
-  线程不共享资源限制(fixed in kernel 2.6.10)。
-  线程不共享间隔定时器(fixed in kernel 2.6.12)。
-  只有主线程允许调用setsid(2)创建新会话(fixed in kernel 2.6.16)。
-  只有主线程允许调用setpgid(2)创建进程组(fixed in kernel 2.6.16)。
-  线程有不同的备用信号栈设置。然而,一个新线程的备用信号栈设置是从创建线程拷贝而来,因此线程被初始化为共享备用信号栈。(fixed in kernel 2.6.16)。
记下下面与实现有关的进一步说明:
-  如果栈大小的软资源限制(参见setrlimit(2)的有关RLIMIT_STACK的描述)被设置为一个不是“不限制”的值,则此值定义新线程的默认栈大小。为使之生效,此限制必须在程序执行之前设置,也许可以用shell的内建命令ulimit -s(Cshell是limit stacksize)
确定线程的具体实现
glibc 2.3.2往后,getconf(1)命令可以被用于确定系统的线程实现,例如:
bash$ getconf GNU_LIBPTHREAD_VERSION
NPTL 2.3.4
更老一些的glibc版本,下面的命令足够确定默认的线程实现:
bash$ $( ldd /bin/ls | grep libc.so | awk '{print $3}' ) | egrep -i 'threads|nptl'
Native POSIX Threads Library by Ulrich Drepper et al
选择线程实现:LD_ASSUME_KERNEL
如果系统上的glibc同时支持Linux线程和NPTL(亦即glibc 2.3.x),LD_ASSUME_KERNEL环境变量可以用于覆盖动态链接器的默认选择。此变量告诉动态链接器假设自己运行在特定内核版本。指定一个不支持NPTL的内核版本,我们可以强制使用Linux线程。(这么做的最可能原因是运行一个依赖Linux线程的一些非标准的行为的应用)例如:
bash$ $( LD_ASSUME_KERNEL=2.2.5 ldd /bin/ls | grep libc.so |  awk '{print $3}' ) | egrep -i 'threads|ntpl'
linuxthreads-0.10 by Xavier Leroy
SEE ALSO
       clone(2), futex(2), gettid(2), proc(5), futex(7), signal(7),
       and  various  Pthreads manual pages, for example: pthread_attr_init(3),
       pthread_atfork(3),     pthread_cancel(3),      pthread_cleanup_push(3),
       pthread_cond_signal(3),     pthread_cond_wait(3),    pthread_create(3),
       pthread_detach(3), pthread_equal(3), pthread_exit(3),  pthread_key_cre‐
       ate(3),             pthread_kill(3),             pthread_mutex_lock(3),
       pthread_mutex_unlock(3),  pthread_once(3),   pthread_setcancelstate(3),
       pthread_setcanceltype(3),  pthread_setspecific(3),  pthread_sigmask(3),
       and pthread_testcancel(3)
COLOPHON
       This page is part of release 3.23 of the Linux  man-pages  project.   A
       description  of  the project, and information about reporting bugs, can
       be found at http://www.kernel.org/doc/man-pages/.

你可能感兴趣的:(pthreads,—POSIX线程,Linux开发,pthreads,linux,function,signal,linux内核,symlink)