fork问题:
a. fork是昂贵的。内存映像要从父进程拷贝到子进程,所有描述字要在子进程中复制等等。写时拷贝技术(copy-on-write)。
b. fork进程后,需要用进程间通信(IPC)在父子进程之间传递信息。
线程,有时被称为轻权进程(lightweight process)。 创建线程要比创建进程快10~100倍。
进程中的所有线程共享:
1. 全局变量
2. 进程指令
3. 大多数数据
4. 打开的文件(如描述字)
5. 信号处理程序和信号处置
6. 当前工作目录
7. 用户ID和组ID
但是每个线程有:
1. 线程ID
2. 寄存器集合,包括程序计数器和栈指针
3. 栈(用于存放局部变量和返回指针)
4. errno
5. 信号掩码
6. 优先级
#include <pthread.h>
int pthread_create(pthread_t *tid, const pthread_attr_t *attr)
void *(*func)(void *), void *arg);
返回: 成功时返回0,出错时返回正的Exxx值。
typedef unsigned long int pthread_t <bits/pthreadtypes.h>
typedef union { <bits/pthreadtypes.h>
char __size[__SIZEOF_PTHREAD_ATTR_T];
long int __align;
} pthread_attr_t;
#if WORDSIZE == 64 <bits/pthreadtypes.h>
#define __SIZEOF_PTHREAD_ATTR_T 56
#else
#define __SIZEOF_PTHREAD_ATTR_T 36
#endif
tid: 返回新创建线程的ID(thread ID)标识
attr: 要创建的新线程的属性: 优先级,起始栈大小,是否应该是一个守护线程等等。通常使用缺省值,为NULL。
func: 创建线程后要执行的函数
arg: 函数func的参数,如果需要多个参数,可打包成一个结构,然后传递结构的地址。
Pthread函数不设置errno。成功时返回0,出错时返回非0。例如:pthread_create因为超过了对系统线程数目的限制而不能创建新线程,将返回EAGAIN。
#define EAGAIN 11 /* Try again */ <asm-generic/errno-base.h>
#include <pthread.h>
int pthread_join(pthread_t tid, void **status);
返回:成功时为0, 出错时为正Exxx值
等待一个线程终止。
tid: 要等待终止的线程
status: 如果status不为NULL,线程的返回值将存放在status指向的位置。
#include <pthread.h>
pthread_t pthread_self(void)
返回: 调用线程的ID
线程: 可汇合的(joinable)线程(缺省值), 脱离的线程(detached).
当可汇合的线程终止时,其线程ID和退出状态将保留,知道另外一个线程调用pthread_join。
脱离的线程则像守护进程:当它终止时,所有的资源都将释放,我们不能等待它终止。
#include <pthread.h>
int pthread_detach(pthread_t tid);
返回: 成功时为0,出错时为正的Exxx值。
将指定的线程变为脱离的。该函数通常被想脱离自己的线程调用。
#include <pthread.h>
void pthread_exit(void *status);
不返回调用者
如果线程未脱离,其线程ID和退出状态将一直保留到调用进程中的某个其他线程调用pthread_join.
指针status不能指向局部于调用线程的对象,因为线程终止时这些对象也消失了。
线程终止的三种方法:
1. 线程调用 pthread_exit 函数
2. 启动线程的函数指向完毕返回。
3. 进程的main函数返回或者任何线程调用函数exit,进程将终止,线程将随之终止。
线程特定数据
每个系统支持有限数量的线程特定数据项。Posix.1要求这个上限不小于128(每个进程)。
系统(很可能是线程库)为每个进程维护一个结构数组。
#include <pthread.h>
int pthread_once(pthread_once_t *onceptr, void (* init)(void));
int pthread_key_create(pthread_key_t *keyptr, void (* destructor)(void *value));
返回: 成功返回0,出错返回正的Exxx值
通常每当一个使用线程特定数据的函数调用时就要调用pthread_once,但pthread_once使用onceptr所指的变量来保证
每个进程只调用一次init函数。
对于一个进程内的给定键,pthread_key_create只能被调用一次。键通过keyptr指针返回,如果想要的destructor函数
不为NULL,而且线程为这个键存储了值,那么该线程终止时,destructor函数将被调用。
typedef int pthread_once_t; <bits/pthreadtypes.h>
typedef unsigned int pthread_key_t; <bits/pthreadtypes.h>
#include <pthread.h>
void *pthread_getspecific(pthread_key_t key);
返回:指向线程特定数据的指针(可能为空指针)
int pthread_setspecific(pthread_key_t key, const void *value);
返回: 成功时为0,出错时为正的Exxx值
typedef union {
struct __pthread_mutex_s {
int __lock;
unsigned int __count;
int __owner;
#if __WORDSIZE == 64
unsigned int __nusers;
#endif
int __kind;
#if __WORDSIZE == 64
int __spins;
__pthread_list_t __list;
#define __PTHREAD_MUTEX_HAVE_PREV 1
#else
unsigned int __nusers;
__extension__ union {
int __spins;
__pthread_slist_t __list;
};
#endif
} __data;
char __size[__SIZEOF_PTHREAD_MUTEX_T];
long int __align;
} pthread_mutex_t;
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mptr);
int pthread_mutex_unlock(pthread_mutex_t *mptr);
返回:正确时为0,出错时为正Exxx值
如果试图为一个已被其他线程锁住的互斥琐加锁,程序便会阻塞直到该互斥锁被解锁。
如果互斥锁变量是静态分配的,必须将它初始化为常值PTHREAD_MUTEX_INITIALIZER.
#define PTHREAD_MUTEX_INITIALIZER /
{ { 0, 0, 0, 0, 0, { 0 } } }
互斥锁加锁并没有太大的开销。
条件变量
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *cptr, pthread_mutex_t *mptr);
int pthread_cond_signal(pthread_cond_t *cptr);
返回:成功时返回0,出错时为正的Exxx值
typedef union {
struct {
int __lock;
unsigned int __futex;
__extension__ unsigned long long int __total_seq;
__extension__ unsigned long long int __wakeup_seq;
__extension__ unsigned long long int __woken_seq;
void *__mutex;
unsigned int __nwaiters;
unsigned int __broadcast_seq;
} __data;
char __size[__SIZEOF_PTHREAD_COND_T];
__extension__ long long int __align;
} pthread_cond_t;
#define PTHREAD_COND_INITIALIZER /
{ { 0, 0, 0, 0, 0, (void *) 0, 0, 0, 0 } }
#include <pthread.h>
int pthread_cond_broadcast(pthread_cond_t *cptr);
int pthread_cond_timedwait(pthread_cond_t *cptr, pthread_mutex_t *mptr,
const struct timespec *abstime);
返回: 成功返回0, 出错返回正的Exxx值
函数pthread_cond_broadcast唤醒阻塞在该条件变量上的所有线程。
函数pthread_cond_timedwait允许一个线程设置阻塞时间的上限。abstime是一个timespec结构,
指定函数必须返回的系统时间,即使条件变量信号还没有被发出。如果超时发生,则返回ETIME错误。
#define ETIME 62 /* Timer expired */ <asm-generic/errno.h>
struct timespec {
long ts_sec;
long ts_nsec;
};
墨菲定律(Murphy's Law): If there are two or more ways to do something, and one of those ways can
result in a catastrophe, then someone will do it.