版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012570105/article/details/84304370
实验环境介绍
gcc:4.8.5
glibc:glibc-2.17-222.el7.x86_64
os:Centos7.4
kernel:3.10.0-693.21.1.el7.x86_64
线程限制
限制名称
描述
name参数
DESTRUCTOR_ITERATIONS
线程退出时操作系统实现师徒小回县城特定数据的最大次数
_SC_THREAD_DESTRUCTOR_ITERATIONS
KEYS_MAX
进程可以创建的键的最大数目
_SC_THREAD_KEYS_MAX
STACK_MIN
一个线程的栈可用的最小字节数
_SC_THREAD_STACK_MIN
THREADS_MAX
进程可以创建的最大线程数
_SC_THREAD_THREADS_MAX
#include <unistd.h>
#include <stdio.h>
#include <limits.h>
int
main ( void )
{
printf ( "DESTRUCTOR_ITERATIONS = %d\n" , sysconf ( _SC_THREAD_DESTRUCTOR_ITERATIONS) ) ;
printf ( "KEYS_MAX = %d\n" , sysconf ( _SC_THREAD_KEYS_MAX) ) ;
printf ( "STACK_MIN = %d\n" , sysconf ( _SC_THREAD_STACK_MIN) ) ;
printf ( "THREADS_MAX = %d\n" , sysconf ( _SC_THREAD_THREADS_MAX) ) ;
return 0 ;
}
result:
DESTRUCTOR_ITERATIONS = 4
KEYS_MAX = 1024
STACK_MIN = 16384
THREADS_MAX = - 1
限制名称
freebsd 8.0
Linux 3.2.0
maxOS X 10.6.8
Solaris 10
DESTRUCTOR_ITERATIONS
4
4
4
没有确定的限制
KEYS_MAX
256
1024
512
没有确定的限制
STACK_MIN
2048
16384
8192
8192
THREADS_MAX
没有确定的限制
没有确定的限制
没有确定的限制
没有确定的限制
线程属性
pthread接口允许我们通过设置每个对象关联的不同属性来细调线程和同步对象的行为。
如互斥量和互斥量属性,线程与线程属性
有对应的初始化函数和销毁函数以及获取属性值的函数
每个属性也有一个属性设置函数
pthread_attr_init的实现是动态分配属性对象,所以使用pthread_attr_destroy可以释放该内存空间
#include <pthread.h>
int pthread_attr_init ( pthread_attr_t * attr) ;
int pthread_attr_destroy ( pthread_attr_t * attr) ;
posix.1线程属性
如果对线程终止状态不感兴趣的话,可以使用pthread_detach函数让操作系统在线程退出时收回它所占用的资源
名称
描述
freebsd 8.0
Linux 3.2.0
maxOS X 10.6.8
Solaris 10
detachstate
线程的分离状态属性
支持
支持
支持
支持
guardsize
线程栈末尾的警戒缓冲区大小(字节数)
支持
支持
支持
支持
stackaddr
线程栈的最低地址
支持
支持
支持
支持
stacksize
线程栈的最小长度(字节数)
支持
支持
支持
支持
设置线程分离状态
如果想让线程一开始就处于分离状态,就将该属性设置为PTHREAD_CREATE_DETACHED,否则正常启动就是PTHREAD_CREATE_JOINABLE
#include <pthread.h>
int pthread_attr_setdetachstate ( pthread_attr_t * attr, int detachstate) ;
int pthread_attr_getdetachstate ( pthread_attr_t * attr, int * detachstate) ;
#include <unistd.h>
#include <stdio.h>
#include <limits.h>
#include <pthread.h>
int makethread ( void * ( * fn) ( void * ) , void * arg) ;
void * f ( void * arg) ;
pthread_t g_tid = 0 ;
int
main ( void )
{
int ret = makethread ( f, NULL ) ;
if ( ret) {
printf ( "make thread error\n" ) ;
exit ( 1 ) ;
}
sleep ( 3 ) ;
pthread_join ( g_tid, NULL ) ;
printf ( "join child_thread over\n" ) ;
return 0 ;
}
int makethread ( void * ( * fn) ( void * ) , void * arg)
{
int err;
pthread_t tid;
pthread_attr_t attr;
err = pthread_attr_init ( & attr) ;
if ( 0 != err)
return ( err) ;
err = pthread_attr_setdetachstate ( & attr, PTHREAD_CREATE_DETACHED) ;
if ( 0 == err)
err = pthread_create ( & tid, & attr, fn, arg) ;
pthread_attr_destroy ( & attr) ;
g_tid = tid;
return ( err) ;
}
void * f ( void * arg)
{
printf ( "thread_comming!!!\n" ) ;
while ( 1 )
sleep ( 1 ) ;
return ( NULL ) ;
}
result:
[ root@localhost 新建文件夹] # . / main
thread_comming! ! !
join child_thread over
获取、设置线程栈属性
对于posix标准的操作系统来说,并不一定要支持线程栈属性。但是尊徐single UNIX specification中xsi选项的E系统来说,需要支持线程栈属性。
下面的代码将直接设置线程栈的大小,如果线程栈太小,会直接段错误
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <pthread.h>
#include <error.h>
#include <string.h>
void * thread_stack ( void * arg)
{
printf ( "The thread is here\n" ) ;
char p[ 1024 * 1024 * 7 ] ;
int i = 1024 * 1024 * 7 ;
while ( i-- )
p[ i] = 3 ;
printf ( "Get 7M Memory\n" ) ;
char p2[ 1024 * 1020 + 256 ] ;
memset ( p2, 0 , sizeof ( char ) * ( 1024 * 1020 + 256 ) ) ;
printf ( "Get More Memory!!!\n" ) ;
return NULL ;
}
int main ( int argc, char * * argv)
{
pthread_t thread_id;
pthread_attr_t thread_attr;
size_t stack_size;
int err;
err = pthread_attr_init ( & thread_attr) ;
if ( err != 0 )
perror ( "Create attr" ) ;
err = pthread_attr_setdetachstate ( & thread_attr, PTHREAD_CREATE_DETACHED) ;
if ( err != 0 )
perror ( "Create attr" ) ;
err = pthread_attr_getstacksize ( & thread_attr, & stack_size) ;
if ( err != 0 )
perror ( "Create attr" ) ;
printf ( "Default stack size is %u; minimum is %u\n" , stack_size,
PTHREAD_STACK_MIN) ;
err = pthread_attr_setstacksize ( & thread_attr, PTHREAD_STACK_MIN * 1024 ) ;
if ( err != 0 )
perror ( "Create attr" ) ;
err = pthread_attr_getstacksize ( & thread_attr, & stack_size) ;
if ( err != 0 )
perror ( "Get stack size" ) ;
printf ( "Default stack size is %u; minimum is %u\n" , stack_size,
PTHREAD_STACK_MIN) ;
int i = 5 ;
while ( i-- ) {
err = pthread_create ( & thread_id, & thread_attr, thread_stack, NULL ) ;
if ( err != 0 )
perror ( "Create thread" ) ;
}
getchar ( ) ;
printf ( "Main exiting\n" ) ;
pthread_exit ( NULL ) ;
return 0 ;
}
result:
[ root@localhost 新建文件夹] # . / main
Default stack size is 16785408 ; minimum is 16384
Default stack size is 16777216 ; minimum is 16384
The thread is here
The thread is here
The thread is here
The thread is here
The thread is here
Get 7 M Memory
Get More Memory! ! !
Get 7 M Memory
Get More Memory! ! !
Get 7 M Memory
Get More Memory! ! !
Get 7 M Memory
Get More Memory! ! !
Get 7 M Memory
Get More Memory! ! !
Main exiting
线程属性guardsize控制着线程栈末尾之后用以避免栈溢出的扩展内存的大小。默认值得看具体实现,但通常是系统页的大小。如果设置为0,则不提供境界缓冲区。如果我们修改了线程属性stackaddr,系统会认为是我们自己管理栈,进而使警戒缓冲区机制无效,等同于guardsize线程属性设置为0
如果guardsize被修改,操作系统会把它取为页大小的证书倍。如果线程的栈指针溢出到了警戒区域,应用程序就可能通过信号接收到出错信息
#include <pthread.h>
int pthread_attr_setguardsize ( pthread_attr_t * attr, size_t guardsize) ;
int pthread_attr_getguardsize ( pthread_attr_t * attr, size_t * guardsize) ;
Compile and link with - pthread.
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <pthread.h>
#include <error.h>
#include <string.h>
int main ( int argc, char * * argv)
{
pthread_t thread_id;
pthread_attr_t thread_attr;
size_t stack_size;
int err;
err = pthread_attr_init ( & thread_attr) ;
if ( err != 0 )
perror ( "Create attr" ) ;
size_t guard_size = 0 ;
err = pthread_attr_getguardsize ( & thread_attr, & guard_size) ;
if ( 0 != err) {
printf ( "pthread_attr_getguardsize error\n" ) ;
exit ( 1 ) ;
}
printf ( "pthread_attr_getguardsize: %d\n" , guard_size) ;
guard_size = 7999 ;
err = pthread_attr_setguardsize ( & thread_attr, guard_size) ;
if ( 0 != err) {
printf ( "pthread_attr_setguardsize6 error\n" ) ;
exit ( 1 ) ;
}
err = pthread_attr_getguardsize ( & thread_attr, & guard_size) ;
if ( 0 != err) {
printf ( "pthread_attr_getguardsize error\n" ) ;
exit ( 1 ) ;
}
printf ( "after pthread_attr_setguardsize: %d\n" , guard_size) ;
return 0 ;
}
result:
[ root@localhost 新建文件夹] # . / main
pthread_attr_getguardsize: 4096
after pthread_attr_setguardsize: 7999
同步属性
互斥量属性
互斥量有3个属性指的注意:进程共享属性、健壮属性和类型属性
PTHREAD_PROCESS_SHARED、PTHREAD_PROCESS_PRIVATE
进程共享属性测试代码:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <pthread.h>
#ifndef _POSIX_THREAD_PROCESS_SHARED
#error This system does not support process shared mutex
#endif
int shared_mem_id;
int * shared_mem_ptr;
pthread_mutexattr_t mutex_shared_attr;
pthread_mutex_t * mptr;
int
main ( void )
{
pid_t child_pid;
int status, rtn;
if ( ( shared_mem_id = shmget ( IPC_PRIVATE, 1 * sizeof ( pthread_mutex_t) , 0660 ) ) < 0 )
perror ( "shmget" ) , exit ( 1 ) ;
if ( ( shared_mem_ptr = ( int * ) shmat ( shared_mem_id, ( void * ) 0 , 0 ) ) == NULL )
perror ( "shmat" ) , exit ( 1 ) ;
mptr = ( pthread_mutex_t * ) shared_mem_ptr;
if ( ( rtn = pthread_mutexattr_init ( & mutex_shared_attr) ) != 0 )
fprintf ( stderr , "pthreas_mutexattr_init: %s" , strerror ( rtn) ) , exit ( 1 ) ;
if ( ( rtn = pthread_mutexattr_setpshared ( & mutex_shared_attr, PTHREAD_PROCESS_SHARED) ) != 0 )
fprintf ( stderr , "pthread_mutexattr_setpshared %s" , strerror ( rtn) ) , exit ( 1 ) ;
if ( ( rtn = pthread_mutex_init ( mptr, & mutex_shared_attr) ) != 0 )
fprintf ( stderr , "pthread_mutex_init %s" , strerror ( rtn) ) , exit ( 1 ) ;
if ( ( child_pid = fork ( ) ) == 0 ) {
if ( ( rtn = pthread_mutex_lock ( mptr) ) != 0 )
fprintf ( stderr , "child:pthread_mutex_lock %s" , strerror ( rtn) ) , exit ( 1 ) ;
sleep ( 1 ) ;
if ( ( rtn = pthread_mutex_unlock ( mptr) ) != 0 )
fprintf ( stderr , "child:pthread_unmutex_lock %s" , strerror ( rtn) ) , exit ( 1 ) ;
printf ( "child exit\n" ) ;
exit ( 0 ) ;
} else {
sleep ( 1 ) ;
if ( ( rtn = pthread_mutex_lock ( mptr) ) != 0 )
fprintf ( stderr , "parent:pthread_mutex_lock %d" , strerror ( rtn) ) , exit ( 1 ) ;
if ( ( rtn = pthread_mutex_unlock ( mptr) ) != 0 )
fprintf ( stderr , "child:pthread_unmutex_lock %d" , strerror ( rtn) ) , exit ( 1 ) ;
wait ( & status) ;
printf ( "recycle child\n" ) ;
}
return 0 ;
}
result:
[ root@localhost 新建文件夹] # . / main
child exit
recycle child
互斥量健壮属性(与多个进程间共享的互斥量有关):进程终止时,互斥量处于锁定状态,恢复起来很困难。
PTHREAD_MUTEX_STALLED:当健壮属性取值为这个值的时,意味着持有互斥量的进程终止时不采取特别的动作,这样使用互斥量后的行为是未定义的
PTHREAD_MUTEX_ROBUST:这个值会导致调用pthread_mutex_lock获取锁的进程a的线程当锁被另外一个进程b的线程占有,并且进程b线程终止时并没有对该锁进行解锁,此时a进程的线程会阻塞,从pthread_mutex_lock返回的值为EOWNERRERAD而不是0,进程a的线程通过这个特殊值获知。如果进程a的线程想继续获取锁,得使用pthread_mutex_consistent
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <errno.h>
#include <pthread.h>
#ifndef _POSIX_THREAD_PROCESS_SHARED
#error This system does not support process shared mutex
#endif
int shared_mem_id;
int * shared_mem_ptr;
pthread_mutexattr_t mutex_shared_attr;
pthread_mutex_t * mptr;
int
main ( void )
{
pid_t child_pid;
int status, rtn;
if ( ( shared_mem_id = shmget ( IPC_PRIVATE, 1 * sizeof ( pthread_mutex_t) , 0660 ) ) < 0 )
perror ( "shmget" ) , exit ( 1 ) ;
if ( ( shared_mem_ptr = ( int * ) shmat ( shared_mem_id, ( void * ) 0 , 0 ) ) == NULL )
perror ( "shmat" ) , exit ( 1 ) ;
mptr = ( pthread_mutex_t * ) shared_mem_ptr;
if ( ( rtn = pthread_mutexattr_init ( & mutex_shared_attr) ) != 0 )
fprintf ( stderr , "pthreas_mutexattr_init: %s" , strerror ( rtn) ) , exit ( 1 ) ;
if ( ( rtn = pthread_mutexattr_setpshared ( & mutex_shared_attr, PTHREAD_PROCESS_SHARED) ) != 0 )
fprintf ( stderr , "pthread_mutexattr_setpshared %s" , strerror ( rtn) ) , exit ( 1 ) ;
if ( ( rtn = pthread_mutexattr_setrobust ( & mutex_shared_attr, PTHREAD_MUTEX_ROBUST) ) != 0 )
fprintf ( stderr , "pthread_mutexattr_setrobust %s" , strerror ( rtn) ) , exit ( 1 ) ;
if ( ( rtn = pthread_mutex_init ( mptr, & mutex_shared_attr) ) != 0 )
fprintf ( stderr , "pthread_mutex_init %s" , strerror ( rtn) ) , exit ( 1 ) ;
if ( ( child_pid = fork ( ) ) == 0 ) {
if ( ( rtn = pthread_mutex_lock ( mptr) ) != 0 )
fprintf ( stderr , "child:pthread_mutex_lock %s" , strerror ( rtn) ) , exit ( 1 ) ;
sleep ( 1 ) ;
printf ( "child exit\n" ) ;
exit ( 0 ) ;
} else {
sleep ( 1 ) ;
if ( ( rtn = pthread_mutex_lock ( mptr) ) != 0 )
fprintf ( stderr , "parent:pthread_mutex_lock %d, %s" , strerror ( rtn) , ( EOWNERDEAD == rtn) ? "EOWNERDEAD" : "UNKNOWN" ) , exit ( 1 ) ;
if ( ( rtn = pthread_mutex_unlock ( mptr) ) != 0 )
fprintf ( stderr , "child:pthread_unmutex_lock %d" , strerror ( rtn) ) , exit ( 1 ) ;
wait ( & status) ;
printf ( "recycle child\n" ) ;
}
return 0 ;
}
result:
[ root@localhost 新建文件夹] # . / main
child exit
parent: pthread_mutex_lock - 853442408 , EOWNERDEAD[ root@localhost 新建文件夹] #
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#define handle_error_en(en, msg) \
do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
static pthread_mutex_t mtx;
static void *
original_owner_thread ( void * ptr)
{
printf ( "[original owner] Setting lock...\n" ) ;
pthread_mutex_lock ( & mtx) ;
printf ( "[original owner] Locked. Now exiting without unlocking.\n" ) ;
pthread_exit ( NULL ) ;
}
int
main ( int argc, char * argv[ ] )
{
pthread_t thr;
pthread_mutexattr_t attr;
int s;
pthread_mutexattr_init ( & attr) ;
pthread_mutexattr_setrobust ( & attr, PTHREAD_MUTEX_ROBUST) ;
pthread_mutex_init ( & mtx, & attr) ;
pthread_create ( & thr, NULL , original_owner_thread, NULL ) ;
sleep ( 2 ) ;
printf ( "[main thread] Attempting to lock the robust mutex.\n" ) ;
s = pthread_mutex_lock ( & mtx) ;
if ( s == EOWNERDEAD) {
printf ( "[main thread] pthread_mutex_lock() returned EOWNERDEAD\n" ) ;
printf ( "[main thread] Now make the mutex consistent\n" ) ;
s = pthread_mutex_consistent ( & mtx) ;
if ( s != 0 )
handle_error_en ( s, "pthread_mutex_consistent" ) ;
printf ( "[main thread] Mutex is now consistent; unlocking\n" ) ;
s = pthread_mutex_unlock ( & mtx) ;
if ( s != 0 )
handle_error_en ( s, "pthread_mutex_unlock" ) ;
exit ( EXIT_SUCCESS) ;
} else if ( s == 0 ) {
printf ( "[main thread] pthread_mutex_lock() unexpectedly succeeded\n" ) ;
exit ( EXIT_FAILURE) ;
} else {
printf ( "[main thread] pthread_mutex_lock() unexpectedly failed\n" ) ;
handle_error_en ( s, "pthread_mutex_lock" ) ;
}
}
result:
[ root@localhost 新建文件夹] # . / main
[ original owner] Setting lock. . .
[ original owner] Locked. Now exiting without unlocking.
[ main thread] Attempting to lock the robust mutex.
[ main thread] pthread_mutex_lock ( ) returned EOWNERDEAD
[ main thread] Now make the mutex consistent
[ main thread] Mutex is now consistent; unlocking
类型属性:控制着互斥量的锁定类型
PTHREAD_MUTEX_NORMAL:标准互斥量类型,不做任何特殊的错误检查或死锁检测
PTHREAD_MUTEX_ERRORCHECK:此互斥量类型提供错误检查
PTHREAD_MUTEX_RECURSIVE:此互斥量类型允许同一个线程在互斥量解锁之前进行多次加锁,加锁几次,就得释放几次。(不适合用于条件变量)
PTHREAD_MUTEX_DEFAULT:此互斥量类型可以提供默认特性和行为。(具体看操作系统是把这种类型指定为上述三种中哪一种)
行为如下:
互斥量类型
没有解锁时重新加锁?
不占用时解锁?
在已解锁时解锁?
PTHREAD_MUTEX_NORMAL
死锁
未定义
未定义
PTHREAD_MUTEX_ERRORCHECK
返回错误
返回错误
返回错误
PTHREAD_MUTEX_RECURSIVE
允许
返回错误
返回错误
PTHREAD_MUTEX_DEFAULT
未定义
未定义
未定义
读写锁属性
条件变量属性
两个属性:进程共享属性和时钟属性
进程共享属性
时钟属性:控制计算pthread_cond_timedwait函数超时参数tsptr时采用的是哪个时钟(CLOCK_REALTIME、CLOCK_MONOTONIC)
屏障属性