[APUE chapter 12] 线程控制
2016-11-02 10:46
447 查看
作者:isshe
日期:2016.10.30
邮箱:i.sshe@outlook.com
github: https://github.com/isshe
就是说与创建线程分离,当新建线程运行结束,就终止线程并释放资源。
默认情况下是不线程分离的,此时新线程运行结束后如果创建线程没有结束就等待创建线程结束,或者使用pthread_join()才能终止新线程,并回收资源。
线程分离方法:(通常在不关心线程终止状态时候使用)
使用pthread_detach函数,线程退出时回收资源。
从一开始就设置线程属性为线程分离:修改pthread_attr_t结构中的detachstate线程属性。
在运行阶段使用_SC_THREAD_ATTR_STACKADDR 和 _SC_THREAD_ATTR_STACKSIZE参数调用sysconf检查系统是否支持线程栈属性。
当修改线程属性stackaddr时,会使警戒区无效,即guardsize==0。
互斥量用于保护条件变量关联的条件。在阻塞线程之前,pthread_cond_wait和pthread_cond_timewait函数释放与条件相关的互斥量。(注意!!!这个可以解答上一个博文的疑问)
如果一个函数对多个线程来说是可重入的,则这个函数是线程安全的。(但不能说明对信号处理程序来说是可重入的)
线程安全:如果一个函数在同一个时间点被多个线程安全地调用,则此函数是线程安全的。
测试操作系统是否支持线程安全函数的方法:
编译时,测试_POSIX_THREAD_SAFE_FUNCTIONS。
运行时,sysconf函数传入_SC_THREAD_SAFE_FUNCTIONS参数。
造成线程不安全的情况:
函数返回的数据存放在静态的内存缓冲区中。
*
功能:
init:初始化一个pthread_attr_t结构。
destroy:反初始化pthread_attr_t结构。
参数:
attr:指向pthread_attr_t 结构的指针。
注意:
使用pthread_attr_init后,attr指向的结构的内容就是当前操作系统的线程属性的默认值。
如果pthread_attr_inin**的实现**对属性对象的内存空间是动态分配的,则pthread_attr_destroy会释放内存空间。
功能:
setdetachstate:设置pthread_attr_t结构的detachstate属性为PTHREAD_CREATE_DETACHED或者PTHREAD_CREATE_JOINABLE。
getdetachstate:获取detachstate属性。(从attr到detachstate)
参数:
attr:指向pthread_attr_t结构的指针。
detachstate: 指向保存分离状态的指针变量。(获取到的状态存到此变量指向的内存中)
功能:设置/获取线程栈属性。
参数:
attr:指向pthread_attr_t结构的指针。
stackaddr:栈的最低内存地址,但并不一定是栈的开始位置。
stacksize:栈大小。
返回值:成功0, 否则错误编号。
功能:设置/获取线程属性stacksize。
参数:略。
返回:成功0,否则错误编号。
功能:设置/获取警戒区域大小。(用以避免栈溢出,通常值为系统页大小)
返回:成功0, 否则错误编号。
注意:
当修改线程属性stackaddr时,会使警戒区无效,即guardsize==0。
如果guardsize线程属性被修改了,操作系统可能会把它取为页大小的整数倍。
功能:
init: 初始化。
destroy: 反初始化。
getpshared:获取进程共享属性。
setpshared:设置进程共享属性。
getrobust:获取健壮的互斥量属性的值。
setrobust:设置健壮的互斥量属性的值。
gettype:获取互斥量类型属性。
settype:设置互斥量类型属性。
类型互斥量属性控制这互斥量的锁定特性。
互斥量类型行为:
* 不占有时解锁:一个线程解锁被另一个线程线程加锁的互斥量。
返回:成功0, 否则错误编号。
功能:
getpshared:获取进程共享属性。(读写锁唯一支持的属性)
setpshared:设置进程共享属性。
参数:略。
返回值:成功0, 否则错误编号。
原型:
功能:
getclock:获取可被用于pthread_cond_timedwait函数的时钟ID。(注意在使用pthread_cond_timedwait前需要用pthread_condattr_t对象对条件变量进程初始化)
setclock:对时钟ID进行修改。
参数:
clock_id:时钟ID。
返回:成功0, 否则错误编号。
功能:略。
参数:略。
返回:成功0,否则错误编号。
功能:锁定标准io的FILE。(注意这个锁是递归的,也就是可以多次锁定的)
参数:略
返回:
ftrylockfile:成功0,若不能获取锁,返回非0值。
其他两个没有返回值。
* 原型:(其实有好多这种函数,只列出书上列出的几个,其他man手册有)
功能:略。
参数:略。
返回:略。
功能:(p359和p360的两个创建键的方法要再学习)
create:创建一个键,还未与线程私有数据值关联。(这个键可以被进程中的所有线程使用,但每个线程把这个键与不同的线程私有(特定)数据地址关联。
delete:取消键与线程私有(特定)数据值的关联关系。
setspecific:把键和线程特定数据关联起来。
getspecific:获取线程私有数据的地址。
参数:
key:指向键的指针。(这是一个值-结果参数)
destructor:析构函数,没有则设为NULL。(pthread_exit, 线程执行返回, 正常退出是会调用,exit/_exit/_Exit/abort不会调用,线程取消时,只有在最后的清理处理程序执行返回后,析构函数才会执行)
pointer:指向需要关联的私有数据地址的指针。
返回:0或错误编号。
这两个属性影响这线程在相应pthread_cancel函数调用时所呈现的行为。
可取消状态有:PTHREAD_CANCEL_DISABLE 和 PTHREAD_CANCEL_ENABLE。
可取消类型有:PTHREADCANEL_DEFERRED 和 PTHREAD_CANCEL_ASYNCHRONOUS。
推迟取消:在遇到取消点才能取消。(取消点在p362)
异步取消:可以在任意时候取消。
功能:
pthread_setcancelstate:修改可取消状态。
pthread_setcanceltype:修改可取消类型。
参数:略。
返回:0或错误编号。
功能:添加自己的取消点。
意味着:某线程修改某信号的处理行为后,所有线程都共享这个处理行为的改变。
进程用sigprocmask函数来阻止信号发送。
线程用pthread_sigmask。
为避免错误,线程在调用sigwait**之前**,必须阻塞那些它正在等待的信号。(返回前恢复)
把信号发送给进程用:kill。
把信号发送给线程用:pthread_kill。
闹钟定时器是进程资源,并且所有的线程共享相同的闹钟。
如果一个信号的动作是终止进程,把此信号传递给某个线程仍然会杀死整个进程。
功能:
设置屏蔽信号集(当set不为NULL时)。
获取屏蔽信号集(当set为NULL且oldset不为NULL时)。
参数:
how:
SIG_BLOCK:把信号机添加到线程信号屏蔽字中。
SIG_SETMASK:用信号集替换线程的信号屏蔽字。
SIG_UNBLOCK:从线程信号屏蔽字中移除信号集。
set:目标操作信号屏蔽集。
oldset:原来的信号屏蔽集。
功能:等待一个或多个信号出现。
参数:
set:指定线程等待的信号集。
sig:返回时,sig指向的整数将包含发送信号的数量。(???)
返回:0或错误编号。
功能:
发送信号给线程。
sig==0时,检查线程是否存在。
如果父进程有一个以上线程,fork后,如果子进程接着不exec,就要清理锁状态。(子进程内部只有一个线程)
可多次调用pthread_atfork函数从而设置多套fork处理函数(疑问:多套如何工作?)。
使用多套时,处理程序的调用顺序是不同的:(这样可以允许多个模块注册它们自己的fork处理函数,而且可以保持锁的层次)
parent和child 是以它们注册时的顺序进行调用。
prepare的调用顺序则和它们注册时相反。
功能:通过此函数建立fork处理函数清除锁状态。(最多可安装3个清理锁的函数)
参数:
prepare:由父进程fork创建子进程前调用,任务是获取父进程定义的所有锁。
parent:fork创建子进程之后、返回之前在父进程上下文中调用,任务是对prepare中获取的所有锁进行解锁。
child:在fork返回前在子进程上下文中调用,任务和parent一样。
注意:不会出现加锁一次解锁两次的情况,prepare获取的锁在fork之后就有了副本。
功能:只进程一次初始化。
参数:
once_contral:必须是一个非本地变量(如全局变量或静态变量)而且必须初始化为PTHREAD_ONCE_INIT。
控制着条件变量时可以被进程的国歌线程使用,还是可以被多个进程的线程使用。
值可为:PTHREAD_PROCESS_SHARED(多进程中的多线程可用) 和 PTHREAD_PROCESS_PRIVATE(初始化该屏障的进程内可以)。
还要再深入。
*
终端输出和重定向结果:
这是一个行缓冲和全缓冲的问题。
标准输出定向到终端时,是行缓冲,每次打印一行。
标准输出定向到文件时,是全缓冲,fork的时候,复制了缓冲区内容,故而有此结果(当缓冲区满或关闭文件的时候,冲洗缓冲区)
12.5 假设可以在一个程序中创建多个线程执行不同的任务,为什么还是可能会需要fork?
可能需要在程序中运行另一个程序(exec)
可能单个进程受到某些限制(如默认单进程最多能打开1024个文件)
csdn:http://download.csdn.net/detail/i_scream_/9670764
github:https://github.com/isshe/2.Advanced_programming/tree/master/chapter_12
日期:2016.10.30
邮箱:i.sshe@outlook.com
github: https://github.com/isshe
1.前言
2. 相关概念
线程分离:就是说与创建线程分离,当新建线程运行结束,就终止线程并释放资源。
默认情况下是不线程分离的,此时新线程运行结束后如果创建线程没有结束就等待创建线程结束,或者使用pthread_join()才能终止新线程,并回收资源。
线程分离方法:(通常在不关心线程终止状态时候使用)
使用pthread_detach函数,线程退出时回收资源。
从一开始就设置线程属性为线程分离:修改pthread_attr_t结构中的detachstate线程属性。
2.1 线程属性
在编译阶段使用_POSIX_THREAD_ATTR_STACKADDR 和 _POSIX_THREAD_ATTR_STACKSIZE来检查系统是否支持线程栈属性。在运行阶段使用_SC_THREAD_ATTR_STACKADDR 和 _SC_THREAD_ATTR_STACKSIZE参数调用sysconf检查系统是否支持线程栈属性。
当修改线程属性stackaddr时,会使警戒区无效,即guardsize==0。
互斥量用于保护条件变量关联的条件。在阻塞线程之前,pthread_cond_wait和pthread_cond_timewait函数释放与条件相关的互斥量。(注意!!!这个可以解答上一个博文的疑问)
2.2 重入
10.6节讨论了可重入函数和信号处理函数,线程在这两个方面也是类似的。如果一个函数对多个线程来说是可重入的,则这个函数是线程安全的。(但不能说明对信号处理程序来说是可重入的)
线程安全:如果一个函数在同一个时间点被多个线程安全地调用,则此函数是线程安全的。
测试操作系统是否支持线程安全函数的方法:
编译时,测试_POSIX_THREAD_SAFE_FUNCTIONS。
运行时,sysconf函数传入_SC_THREAD_SAFE_FUNCTIONS参数。
造成线程不安全的情况:
函数返回的数据存放在静态的内存缓冲区中。
*
2.3 线程私有数据
线程私有数据也叫线程特定数据(thread-specific data),是存储和查询某个特定线程相关数据的一种机制。3. 相关函数
3.1 线程属性相关
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);
功能:
init:初始化一个pthread_attr_t结构。
destroy:反初始化pthread_attr_t结构。
参数:
attr:指向pthread_attr_t 结构的指针。
注意:
使用pthread_attr_init后,attr指向的结构的内容就是当前操作系统的线程属性的默认值。
如果pthread_attr_inin**的实现**对属性对象的内存空间是动态分配的,则pthread_attr_destroy会释放内存空间。
pthread_attr_getdetachstate 和 pthread_attr_setdetachstate
原型:#include <pthread.h> int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate); int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
功能:
setdetachstate:设置pthread_attr_t结构的detachstate属性为PTHREAD_CREATE_DETACHED或者PTHREAD_CREATE_JOINABLE。
getdetachstate:获取detachstate属性。(从attr到detachstate)
参数:
attr:指向pthread_attr_t结构的指针。
detachstate: 指向保存分离状态的指针变量。(获取到的状态存到此变量指向的内存中)
pthread_attr_getstack 和 pthread_attr_setstack
原型:#include <pthread.h> int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize); int pthread_attr_getstack(const pthread_attr_t *attr, void **stackaddr, size_t *stacksize);
功能:设置/获取线程栈属性。
参数:
attr:指向pthread_attr_t结构的指针。
stackaddr:栈的最低内存地址,但并不一定是栈的开始位置。
stacksize:栈大小。
返回值:成功0, 否则错误编号。
pthread_attr_getstacksize 和 pthread_attr_setstacksize
原型:#include <pthread.h> int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize); int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *stacksize);
功能:设置/获取线程属性stacksize。
参数:略。
返回:成功0,否则错误编号。
pthread_attr_getguardsize 和 pthread_attr_setguardsize
原型:#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);
功能:设置/获取警戒区域大小。(用以避免栈溢出,通常值为系统页大小)
返回:成功0, 否则错误编号。
注意:
当修改线程属性stackaddr时,会使警戒区无效,即guardsize==0。
如果guardsize线程属性被修改了,操作系统可能会把它取为页大小的整数倍。
3.2 同步属性
这个知识点不大理解。p345-p348pthread_mutexattr_*(互斥量属性)
原型:#include <pthread.h> int pthread_mutexattr_init(pthread_mutexattr_t *attr); int pthread_mutexattr_destroy(pthread_mutexattr_t *attr); int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind); int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *kind); int pthread_mutexattr_getpshared(const pthread_mutexattr_t *restrict attr, int *restrict pshared); int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared); int pthread_mutexattr_getrobust(const pthread_mutexattr_t *restrict attr, int *restrict robust); int pthread_mutexattr_setrobust(pthread_mutexattr_t *attr, int robust);
功能:
init: 初始化。
destroy: 反初始化。
getpshared:获取进程共享属性。
setpshared:设置进程共享属性。
getrobust:获取健壮的互斥量属性的值。
setrobust:设置健壮的互斥量属性的值。
gettype:获取互斥量类型属性。
settype:设置互斥量类型属性。
类型互斥量属性控制这互斥量的锁定特性。
互斥量类型行为:
互斥量 | 没有解锁时重新加锁 | 不占有时解锁 | 已解锁时解锁 |
---|---|---|---|
PTHREAD_MUTEX_NORMAL | 死锁 | 未定义 | 未定义 |
PTHREAD_MUTEX_ERRORCHECK | 返回错误 | 返回错误 | 返回错误 |
PTHREAD_MUTEX_RECURSIVE | 允许 | 返回错误 | 返回错误 |
PTHREAD_MUTEX_DEFAULT | 未定义 | 未定义 | 未定义 |
返回:成功0, 否则错误编号。
pthread_rwlockattr_*(读写锁属性)
原型:#include <pthread.h> int pthread_rwlockattr_init(pthread_rwlockattr_t *attr); int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr); int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *restrict attr, int *restrict pshared); int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared);
功能:
getpshared:获取进程共享属性。(读写锁唯一支持的属性)
setpshared:设置进程共享属性。
参数:略。
返回值:成功0, 否则错误编号。
pthread_condattr_(条件变量属性)
Single UNIX Specification目前定义了条件变量的两个属性:进程共享属性和时钟属性。原型:
#include <pthread.h> int pthread_condattr_init(pthread_condattr_t *attr); int pthread_condattr_destroy(pthread_condattr_t *attr); int pthread_condattr_getpshared(const pthread_condattr_t *restrict attr, int *restrict pshared); int pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared); int pthread_condattr_getclock(const pthread_condattr_t *restrict attr, clockid_t *restrict clock_id); int pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clock_id);
功能:
getclock:获取可被用于pthread_cond_timedwait函数的时钟ID。(注意在使用pthread_cond_timedwait前需要用pthread_condattr_t对象对条件变量进程初始化)
setclock:对时钟ID进行修改。
参数:
clock_id:时钟ID。
返回:成功0, 否则错误编号。
pthread_barrierattr_*(屏障属性)
原型:#include <pthread.h> int pthread_barrierattr_init(pthread_barrierattr_t *attr); int pthread_barrierattr_destroy(pthread_barrierattr_t *attr); int pthread_barrierattr_getpshared(const pthread_barrierattr_t *restrict attr, int *restrict pshared); int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared);
功能:略。
参数:略。
返回:成功0,否则错误编号。
3.3 重入
lockfile相关
原型:void flockfile(FILE *filehandle); int ftrylockfile(FILE *filehandle); void funlockfile(FILE *filehandle);
功能:锁定标准io的FILE。(注意这个锁是递归的,也就是可以多次锁定的)
参数:略
返回:
ftrylockfile:成功0,若不能获取锁,返回非0值。
其他两个没有返回值。
unlocked的字符操作
为了处理每读写一个字符就获取锁和释放锁一次的开销,可以使用下面函数。(p356)* 原型:(其实有好多这种函数,只列出书上列出的几个,其他man手册有)
#include <stdio.h> int getc_unlocked(FILE *stream); int getchar_unlocked(void); int putc_unlocked(int c, FILE *stream); int putchar_unlocked(int c);
功能:略。
参数:略。
返回:略。
3.4 线程私有数据
在分配线程特定数据之前,需要创建与该数据关联的键。pthread_key相关
原型:#include <pthread.h> int pthread_key_create(pthread_key_t *key, void (*destr_function)(void *)); int pthread_key_delete(pthread_key_t key); int pthread_setspecific(pthread_key_t key, const void *pointer); void * pthread_getspecific(pthread_key_t key);
功能:(p359和p360的两个创建键的方法要再学习)
create:创建一个键,还未与线程私有数据值关联。(这个键可以被进程中的所有线程使用,但每个线程把这个键与不同的线程私有(特定)数据地址关联。
delete:取消键与线程私有(特定)数据值的关联关系。
setspecific:把键和线程特定数据关联起来。
getspecific:获取线程私有数据的地址。
参数:
key:指向键的指针。(这是一个值-结果参数)
destructor:析构函数,没有则设为NULL。(pthread_exit, 线程执行返回, 正常退出是会调用,exit/_exit/_Exit/abort不会调用,线程取消时,只有在最后的清理处理程序执行返回后,析构函数才会执行)
pointer:指向需要关联的私有数据地址的指针。
返回:0或错误编号。
3.5 取消选项
有两个线程属性并没有包含在pthread_attr_t结构中:可取消状态和可取消类型。这两个属性影响这线程在相应pthread_cancel函数调用时所呈现的行为。
可取消状态有:PTHREAD_CANCEL_DISABLE 和 PTHREAD_CANCEL_ENABLE。
可取消类型有:PTHREADCANEL_DEFERRED 和 PTHREAD_CANCEL_ASYNCHRONOUS。
推迟取消:在遇到取消点才能取消。(取消点在p362)
异步取消:可以在任意时候取消。
pthread_setcancelstate和pthread_setcanceltype
原型:#include <pthread.h> int pthread_setcancelstate(int state, int *oldstate); int pthread_setcanceltype(int type, int *oldtype);
功能:
pthread_setcancelstate:修改可取消状态。
pthread_setcanceltype:修改可取消类型。
参数:略。
返回:0或错误编号。
pthread_testcancel
原型:#include <pthread.h> void pthread_testcancel(void);
功能:添加自己的取消点。
3.8 线程和信号
每个线程都有自己的信号屏蔽字(但会继承父线程的),但信号的处理是进程中所有线程共享的。意味着:某线程修改某信号的处理行为后,所有线程都共享这个处理行为的改变。
进程用sigprocmask函数来阻止信号发送。
线程用pthread_sigmask。
为避免错误,线程在调用sigwait**之前**,必须阻塞那些它正在等待的信号。(返回前恢复)
把信号发送给进程用:kill。
把信号发送给线程用:pthread_kill。
闹钟定时器是进程资源,并且所有的线程共享相同的闹钟。
如果一个信号的动作是终止进程,把此信号传递给某个线程仍然会杀死整个进程。
pthread_sigmask
原型:#include <signal.h> int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset);
功能:
设置屏蔽信号集(当set不为NULL时)。
获取屏蔽信号集(当set为NULL且oldset不为NULL时)。
参数:
how:
SIG_BLOCK:把信号机添加到线程信号屏蔽字中。
SIG_SETMASK:用信号集替换线程的信号屏蔽字。
SIG_UNBLOCK:从线程信号屏蔽字中移除信号集。
set:目标操作信号屏蔽集。
oldset:原来的信号屏蔽集。
sigwait
原型:#include <signal.h> int sigwait(const sigset_t *set, int *sig);
功能:等待一个或多个信号出现。
参数:
set:指定线程等待的信号集。
sig:返回时,sig指向的整数将包含发送信号的数量。(???)
返回:0或错误编号。
pthread_kill
原型:#include <signal.h> int pthread_kill(pthread_t thread, int sig);
功能:
发送信号给线程。
sig==0时,检查线程是否存在。
3.9 线程和fork
fork后,子进程会继承互斥量,读写锁,条件变量等。(具体见博客:待补)如果父进程有一个以上线程,fork后,如果子进程接着不exec,就要清理锁状态。(子进程内部只有一个线程)
可多次调用pthread_atfork函数从而设置多套fork处理函数(疑问:多套如何工作?)。
使用多套时,处理程序的调用顺序是不同的:(这样可以允许多个模块注册它们自己的fork处理函数,而且可以保持锁的层次)
parent和child 是以它们注册时的顺序进行调用。
prepare的调用顺序则和它们注册时相反。
pthread_atfork
原型:#include <pthread.h> int pthread_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void));
功能:通过此函数建立fork处理函数清除锁状态。(最多可安装3个清理锁的函数)
参数:
prepare:由父进程fork创建子进程前调用,任务是获取父进程定义的所有锁。
parent:fork创建子进程之后、返回之前在父进程上下文中调用,任务是对prepare中获取的所有锁进行解锁。
child:在fork返回前在子进程上下文中调用,任务和parent一样。
注意:不会出现加锁一次解锁两次的情况,prepare获取的锁在fork之后就有了副本。
4. 拓展知识
对进程来说,虚地址空间的大小是固定的。4.1 pthread_once
原型:#include <pthread.h> pthread_once_t once_control = PTHREAD_ONCE_INIT; int pthread_once(pthread_once_t *once_control, void (*init_routine)(void));
功能:只进程一次初始化。
参数:
once_contral:必须是一个非本地变量(如全局变量或静态变量)而且必须初始化为PTHREAD_ONCE_INIT。
5. 疑问
什么时进程共享属性?控制着条件变量时可以被进程的国歌线程使用,还是可以被多个进程的线程使用。
值可为:PTHREAD_PROCESS_SHARED(多进程中的多线程可用) 和 PTHREAD_PROCESS_PRIVATE(初始化该屏障的进程内可以)。
还要再深入。
*
6. 习题
12.1 在linux系统中运行图12-17,把输出结果重定向到文件,解释结果。终端输出和重定向结果:
这是一个行缓冲和全缓冲的问题。
标准输出定向到终端时,是行缓冲,每次打印一行。
标准输出定向到文件时,是全缓冲,fork的时候,复制了缓冲区内容,故而有此结果(当缓冲区满或关闭文件的时候,冲洗缓冲区)
12.5 假设可以在一个程序中创建多个线程执行不同的任务,为什么还是可能会需要fork?
可能需要在程序中运行另一个程序(exec)
可能单个进程受到某些限制(如默认单进程最多能打开1024个文件)
7. 参考资料
《unix环境高级编程》第12章8. 相关下载
12章代码下载:csdn:http://download.csdn.net/detail/i_scream_/9670764
github:https://github.com/isshe/2.Advanced_programming/tree/master/chapter_12
相关文章推荐
- APUE Chapter 12笔记:Unix下线程的控制(I)
- APUE Chapter 12笔记:Unix下线程的控制(III)
- APUE Chapter 12笔记:Unix下线程的控制(II)
- APUE读书笔记-12线程控制-11总结
- APUE 学习笔记——线程控制
- apue 第12章 线程控制
- APUE读书笔记-12线程控制-06线程特定数据
- APUE读书笔记-12线程控制-01简介
- APUE读书笔记-12线程控制-05可重入性
- APUE读书笔记-12线程控制-07取消相关的选项
- APUE读书笔记-12线程控制-02线程限制
- 12线程控制
- APUE读书笔记-12线程控制-03线程属性
- apue 第十二章 线程控制
- APUE 阅读笔记(chapter 11&12)——线程
- [APUE]第十二章 线程控制
- Chapter 12 线程控制
- APUE读书笔记-12线程控制-04同步属性
- APUE读书笔记-12线程控制-08线程和信号
- [APUE]第十二章 线程控制