[译] man 7 pthreads

NAME
     pthreads - POSIX threads
 
DESCRIPTION
     POSIX.1 指定了一组叫做POSIX线程或Pthreads的编程接口(函数,头文件)。单个进程可以包含多个线程,所有线程执行相同的程序。这些线程共享相同的全局存储空间(数据段和堆),但每个线程有其自己的栈(自动变量)。
 
     POSIX.1 也要求共享一些其它属性(例如,进程范围内而不是每个线程的属性)
  • 进程ID
  • 父进程ID
  • 进程组ID和会话ID
  • 控制终端
  • 用户和组IDs
  • 打开的文件描述符
  • 记录锁(参考fcntl(2))
  • 信号处理
  • 文件创建掩码模式(umask(2))
  • 当前目录(chdir(2))和root目录(chroot(2))
  • 定时器(settimer(2))和POSIX定时器(timer_create(2))
  • 优先级值(setpriority(2))
  • 资源限制(setrlimit(2))
  • CPU使用时间(times(2))和资源使用情况的测量值
 
     和栈一样,POSIX.1指出,对于各个线程其它各属性是不同的,包括:
  • 线程ID(pthread_t数据类型)
  • 信号掩码(pthread_sigmask(3))
  • errno变量
  • 替换信号处理栈
  • 实时调度策略和优先级(shed_setscheduler(2)和sched_setparam(2))
 
     下面是只是Linux系统的特点,对于每个线程都不同:
  • capabilities(capabilities(7))
  • CPU affinity(sched_setaffinity(2))
     线程函数返回值
     大多数线程函数成功后返回0,失败后返回错误码。注意线程函数不会设置errno值,对每个能返回错误码的线程函数,POSIX.1指定这种函数对于错误EINTR永远也不会失败。
 
     线程ID
     在一个进程中每个线程都有唯一一个线程ID(保存在pthread_t类型中),这个ID通过调用pthread_create(3)得到,一个线程可以通过pthread_self()得到其自身线程ID,线程ID仅在进程范围内是唯一的,一个线程ID还能被重新利用,例如,在一个终止线程在被回收后,或者一个分离的线程终止后,这个线程ID可能被新的线程使用。在所有接收线程ID作为参数的线程函数中,这个ID实际指向相同调用进程中的线程。
 
     线程安全函数
     一个线程安全函数可以同时被多个线程安全地调用(例如,不管是什么都能给出相同的结果)。
     POSIX.1-2001  和 POSIX.1-2008 要求所有在标准中指定的函数是线程安全的,除了下面的函数
           asctime()                                                    
           basename()                                                   
           catgets()                                                    
           crypt()                                                      
           ctermid() if passed a non-NULL argument                      
           ctime()                                                      
           dbm_clearerr()                                               
           dbm_close()                                                  
           dbm_delete()                                                 
           dbm_error()                                                  
           dbm_fetch()                                                  
           dbm_firstkey()                                               
           dbm_nextkey()                                                
           dbm_open()                                                   
           dbm_store()                                                  
           dirname()                                                    
           dlerror()                                                    
           drand48()                                                    
           ecvt() [POSIX.1-2001 only (function removed in POSIX.1-2008)]
           encrypt()                                                    
           endgrent()                                                   
           endpwent()                                                   
           endutxent()                                                  
           fcvt() [POSIX.1-2001 only (function removed in POSIX.1-2008)]
           ftw()                                                        
           gcvt() [POSIX.1-2001 only (function removed in POSIX.1-2008)]
           getc_unlocked()                                              
           getchar_unlocked()                                           
           getdate()                                                    
           getenv()                                                            
           getgrent()                                                          
           getgrgid()                                                          
           getgrnam()                                                          
           gethostbyaddr() [POSIX.1-2001 only (function removed in POSIX.1-2008)]
           gethostbyname() [POSIX.1-2001 only (function removed in POSIX.1-2008)]
           gethostent()                                                        
           getlogin()                                                          
           getnetbyaddr()                                                      
           getnetbyname()                                                      
           getnetent()                                                         
           getopt()                                                            
           getprotobyname()                                                    
           getprotobynumber()                                                  
           getprotoent()                                                       
           getpwent()                                                          
           getpwnam()                                                          
           getpwuid()                                                          
           getservbyname()                                                     
           getservbyport()                                                     
           getservent()                                                        
           getutxent()                                                         
           getutxid()                                                          
           getutxline()                                                        
           gmtime()                                                            
           hcreate()                                                           
           hdestroy()                                                          
           hsearch()                                                           
           inet_ntoa()                                                         
           l64a()                                                              
           lgamma()                                                            
           lgammaf()                                                           
           lgammal()                               
           localeconv()                            
           localtime()                             
           lrand48()                               
           mrand48()                               
           nftw()                                  
           nl_langinfo()                           
           ptsname()                               
           putc_unlocked()                         
           putchar_unlocked()                      
           putenv()                                
           pututxline()                            
           rand()                                  
           readdir()                               
           setenv()                                
           setgrent()                              
           setkey()                                
           setpwent()                              
           setutxent()                             
           strerror()                              
           strsignal() [Added in POSIX.1-2008]     
           strtok()                                
           system() [Added in POSIX.1-2008]        
           tmpnam() if passed a non-NULL argument  
           ttyname()                               
           unsetenv()                              
           wcrtomb() if its final argument is NULL 
           wcsrtombs() if its final argument is NULL
           wcstombs()                              
           wctomb()                                 
 
     异步撤销安全函数
     一个异步撤销安全函数是当异步撤销能力被启用后,在应用中可以被安全地调用。
     仅仅下面的函数在POSIX.1-2001和POSIX.1-2008要求是异步线程安全的:
           pthread_cancel()       
           pthread_setcancelstate()
           pthread_setcanceltype()
 
     撤销点
     POSIX.1 指定一些确定的函数必须是撤销点,而还有一些函数可能是撤销点。如果一个线程是可以撤销的,它的撤销类型是延迟的,一个撤销请求对那个线程还是未决的,然后当它调用一个撤销点时线程被撤销。
     下面的函数POSIX.1-2001和/或POSIX.1-2008要求是撤销点:
           accept()
           aio_suspend()
           clock_nanosleep()
           close()
           connect()
           creat()
           fcntl() F_SETLKW
           fdatasync()
           fsync()
           getmsg()
           getpmsg()
           lockf() F_LOCK
           mq_receive()
           mq_send()
           mq_timedreceive()
           mq_timedsend()
           msgrcv()
           msgsnd()
           msync()
           nanosleep()
           open()
           openat() [Added in POSIX.1-2008]
           pause()
           poll()
           pread()
           pselect()
           pthread_cond_timedwait()
           pthread_cond_wait()
           pthread_join()
           pthread_testcancel()
           putmsg()
           putpmsg()
           pwrite()
           read()
           readv()
           recv()
           recvfrom()
           recvmsg()
           select()
           sem_timedwait()
           sem_wait()
           send()
           sendmsg()
           sendto()
           sigpause() [POSIX.1-2001 only (moves to "may" list in POSIX.1-2008)]
           sigsuspend()
           sigtimedwait()
           sigwait()
           sigwaitinfo()
           sleep()
           system()
           tcdrain()
           usleep() [POSIX.1-2001 only (function removed in POSIX.1-2008)]
           wait()
           waitid()
           waitpid()
           write()
           writev()
 
     下面的函数根据POSIX.1-2001和/或POSIX.1-2008或许可能是撤销点:
           access()
           asctime()
           asctime_r()
           catclose()
           catgets()
           catopen()
           chmod() [Added in POSIX.1-2008]
           chown() [Added in POSIX.1-2008]
           closedir()
           closelog()
           ctermid()
           ctime()
           ctime_r()
           dbm_close()
           dbm_delete()
           dbm_fetch()
           dbm_nextkey()
           dbm_open()
           dbm_store()
           dlclose()
           dlopen()
           dprintf() [Added in POSIX.1-2008]
           endgrent()
           endhostent()
           endnetent()
           endprotoent()
           endpwent()
           endservent()
           endutxent()
           faccessat() [Added in POSIX.1-2008]
           fchmod() [Added in POSIX.1-2008]
           fchmodat() [Added in POSIX.1-2008]
           fchown() [Added in POSIX.1-2008]
           fchownat() [Added in POSIX.1-2008]
           fclose()
           fcntl() (for any value of cmd argument)
           fflush()
           fgetc()
           fgetpos()
           fgets()
           fgetwc()
           fgetws()
           fmtmsg()
           fopen()
           fpathconf()
           fprintf()
           fputc()
           fputs()
           fputwc()
           fputws()
           fread()
           freopen()
           fscanf()
           fseek()
           fseeko()
           fsetpos()
           fstat()
           fstatat() [Added in POSIX.1-2008]
           ftell()
           ftello()
           ftw()
           futimens() [Added in POSIX.1-2008]
           fwprintf()
           fwrite()
           fwscanf()
           getaddrinfo()
           getc()
           getc_unlocked()
           getchar()
           getchar_unlocked()
           getcwd()
           getdate()
           getdelim() [Added in POSIX.1-2008]
           getgrent()
           getgrgid()
           getgrgid_r()
           getgrnam()
           getgrnam_r()
           gethostbyaddr() [SUSv3 only (function removed in POSIX.1-2008)]
           gethostbyname() [SUSv3 only (function removed in POSIX.1-2008)]
           gethostent()
           gethostid()
           gethostname()
           getline() [Added in POSIX.1-2008]
           getlogin()
           getlogin_r()
           getnameinfo()
           getnetbyaddr()
           getnetbyname()
           getnetent()
           getopt() (if opterr is nonzero)
           getprotobyname()
           getprotobynumber()
           getprotoent()
           getpwent()
           getpwnam()
           getpwnam_r()
           getpwuid()
           getpwuid_r()
           gets()
           getservbyname()
           getservbyport()
           getservent()
           getutxent()
           getutxid()
           getutxline()
           getwc()
           getwchar()
           getwd() [SUSv3 only (function removed in POSIX.1-2008)]
           glob()
           iconv_close()
           iconv_open()
           ioctl()
           link()
           linkat() [Added in POSIX.1-2008]
           lio_listio() [Added in POSIX.1-2008]
           localtime()
           localtime_r()
           lockf() [Added in POSIX.1-2008]
           lseek()
           lstat()
           mkdir() [Added in POSIX.1-2008]
           mkdirat() [Added in POSIX.1-2008]
           mkdtemp() [Added in POSIX.1-2008]
           mkfifo() [Added in POSIX.1-2008]
           mkfifoat() [Added in POSIX.1-2008]
           mknod() [Added in POSIX.1-2008]
           mknodat() [Added in POSIX.1-2008]
           mkstemp()
           mktime()
           nftw()
           opendir()
           openlog()
           pathconf()
           pclose()
           perror()
           popen()
           posix_fadvise()
           posix_fallocate()
           posix_madvise()
           posix_openpt()
           posix_spawn()
           posix_spawnp()
           posix_trace_clear()
           posix_trace_close()
           posix_trace_create()
           posix_trace_create_withlog()
           posix_trace_eventtypelist_getnext_id()
           posix_trace_eventtypelist_rewind()
           posix_trace_flush()
           posix_trace_get_attr()
           posix_trace_get_filter()
           posix_trace_get_status()
           posix_trace_getnext_event()
           posix_trace_open()
           posix_trace_rewind()
           posix_trace_set_filter()
           posix_trace_shutdown()
           posix_trace_timedgetnext_event()
           posix_typed_mem_open()
           printf()
           psiginfo() [Added in POSIX.1-2008]
           psignal() [Added in POSIX.1-2008]
           pthread_rwlock_rdlock()
           pthread_rwlock_timedrdlock()
           pthread_rwlock_timedwrlock()
           pthread_rwlock_wrlock()
           putc()
           putc_unlocked()
           putchar()
           putchar_unlocked()
           puts()
           pututxline()
           putwc()
           putwchar()
           readdir()
           readdir_r()
           readlink() [Added in POSIX.1-2008]
           readlinkat() [Added in POSIX.1-2008]
           remove()
           rename()
           renameat() [Added in POSIX.1-2008]
           rewind()
           rewinddir()
           scandir() [Added in POSIX.1-2008]
           scanf()
           seekdir()
           semop()
           setgrent()
           sethostent()
           setnetent()
           setprotoent()
           setpwent()
           setservent()
           setutxent()
           sigpause() [Added in POSIX.1-2008]
           stat()
           strerror()
           strerror_r()
           strftime()
           symlink()
           symlinkat() [Added in POSIX.1-2008]
           sync()
           syslog()
           tmpfile()
           tmpnam()
           ttyname()
           ttyname_r()
           tzset()
           ungetc()
           ungetwc()
           unlink()
           unlinkat() [Added in POSIX.1-2008]
           utime() [Added in POSIX.1-2008]
           utimensat() [Added in POSIX.1-2008]
           utimes() [Added in POSIX.1-2008]
           vdprintf() [Added in POSIX.1-2008]
           vfprintf()
           vfwprintf()
           vprintf()
           vwprintf()
           wcsftime()
           wordexp()
           wprintf()
           wscanf()
 
     具体实现或许会标记其它非标准指定的撤销函数,特别地,具体实现可能会标记出其它任何阻塞的非标准函数作为撤销点。(这包括大多数可能生成文件的函数)
 
     在Linux上编译多线程程序
     在Linux上,程序使用了Phtreads API应该使用 cc -pthread来编译。
 
     POSIX线程的Linux实现
     随着时间的推移,在GNU C库中提供两种线程的实现
  • LinuxThreads: 这是原始的Pthreads实现,从glibc 2.4以后,这种实现不再被支持。
  • NPTL: (Native POSIX Threads Library)这种实现比较新,与LinuxThreds相比,NPTL提供了与POSIX.1规范更近的一致性,当创建大量线程时也有更好的性能,NPTL从glibc 2.3.2以后都是可用的,并且需要在Linux 2.6 内核中提供的特性。
     这两种实现被称之为1:1实现,意思是每个线程映射到内核调度实体,两种实现都是通过Linux clone(2)系统调用来实现,在NPTL,线程同步原语(mutexes,线程终止等待)使用futex(2)系统调用实现。
 
     LinuxThreads
     这种实现值得注意的特性如下:
  • 除了主(初始)线程,使用pthread_create(3)创建的线程,在实现中创建了一个“管理者”线程。这个线程处理线程创建和终止。(如果这个线程被不经意地杀死后,可能会导致问题出现)
  • 在实现的内部使用了信号。在Linux 2.2以后,使用了前三个实时信号,在更旧的Linux内核中,SIGUSR1和SIGUSR2被使用,应用程序要避免使用被线程实现使用的信号。
  • 线程不共享进程IDs。(实际上,LinuxThreads线程实现为比常用进程共享更多信息的进程,但是不共享通用进程ID。)LinuxThreads(包括管理线程)在使用ps(1)是都能作为分离的进程被看到。
 
     LinuxThreads实现在很多方面偏离了POSIX.1规范,包括如下:
  • 调用getpid(2)返回每个线程的不同值。
  • 在线程中而不是主线程中调用getppid(2)返回管理线程的进程ID;在这些线程中getppid(2)的返回值应该返回与主线程中getppid(2)相同的值。
  • 当一个线程使用fork(2)创建一个子进程时,任何线程应该能能够在其子进程上wait(2)。然而,实现仅仅允许创建了子进程的那个线程执行wait(2)。
  • 当一个线程调用execve(2),所有其它线程被终止(POSIX.1要求)。然而,最终的进程使用了与与调用execve(2)线程相同的PID,应该是与主线有相同的PID。
  • 线程不共享用户和组IDs,如果应用通过使用seteuid(2)或其它类似函数改变了其相关内容,这就会对设置用户ID程序造成问题,在线程函数中会导致失败。
  • 线程不共享公用的会话ID和进程组ID。
  • 线程不共享使用fcntl(2)创建的记录锁。
  • times(2)和getrusage(2)返回的信息是每个线程级别的而不是进程级别的。
  • 线程不共享信号量撤销值(参考semop(2))。
  • 线程不共享间隔定时器。
  • 线程不共享公用优先级值。
  • POSIX.1 区分指向整个进程的信号和单个线程的信号。根据POSIX.1,一个指向进程的信号(使用kill发送)应该被进程中单个选定的线程来处理。LinuxThreads不支持指向进程进程的信号:信号只能发送给特定的线程。
  • 线程有不同的替换信号栈设置,一个新的线程的替换信号栈设置从创建了线程的线程中拷贝而来,所以线程初始时是共享替换信号栈的。(一个新的线程应该使用未定义的替换信号栈启动,如果两个线程在同一时刻处理信号使用共享的替换信号栈,不可预测的程序失败可能出现)。
     NPTL
     使用NPTL,在进程中的所有线程放在相同的线程组中;线程组中的所有成员共享相同的PID,NPTL不使用管理者线程,NPTL在内部使用前两个实时信号(参看signal(7));这些信号不能被应用程序使用。
     NPTL至少还与POSIX.1有下面的不一致:
  • 线程不共享公用的优先级值
 
     一些其它的NPTL不一致仅仅出现在老版本内核中:
  • 使用times(2)和getrusage(2)返回的信息是线程级的而不是进程范围内的(在内核2.6.9中修复)。
  • 线程不共享资源限制(在内核2.6.10中修复)。
  • 线程不共享间隔定时器(在内核2.6.12中修复)。
  • 仅仅主线程被允许使用setsid(2)来开启一个新的会话(在内核2.6.16中修复)。
  • 仅仅主线程被允许使用setpgid(2)使得一个进程成为进程组leader(在内核2.6.16中修复)。
  • 线程拥有不同的替换信号栈设置,然而,一个新线程的替换信号栈设定是从创建它的线程中拷贝而来,所以初始时共享替换信号处理栈(在内核2.6.16中修复)。
 
     注意下面的更多关于NPTL实现:
  • 如果栈大小软资源限制(查看setrlimit(2)中RLIMIT_STACK中的描述)被设置成除了unlimited之外的值,这个值定义了新线程的默认栈大小。为了生效,这个限制必须在程序运行前设置,也许可以使用ulimit -s这个shell内置的命令。
     确定线程实现
     从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
     在支持LinuxThreads和NPTL(例如,glibc 2.3.x)的系统上,LD_ASSUME_KERNEL环境变量可以被用来重写动态链接器的线程实现的默认选项,这个变量指示动态链接器用来给出其运行在特殊内核版本之上。通过指定不支持NPTL的内核版本,可以强制使用LinuxThreads。(这样做常见的原因就是就是为了运行依赖于在LinuxThreads中一些不一致的特性(不工作)应用。)例如:
 
SEE ALSO
       clone(2), futex(2), gettid(2), proc(5), futex(7), sigevent(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_create(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), pthread_sigqueue(3), and pthread_testcancel(3)
 
COLOPHON
       This page is part of release 3.35 of the Linux man-pages project.  A description of the project, and information about reporting bugs, can be found at http://man7.org/linux/man-pages/.
原文地址:https://www.cnblogs.com/wangshide/p/3165084.html