pag288
进程的所有信息对该进程的所有线程都是共享的,包括可执行的程序文本、程序的全局内存和堆内存、栈以及文件描述符。
进程ID在整个系统中是唯一的,线程ID只在他所属的进程环境中有效。
int pthread_equal(pthread_t tid1, pthread_t tid2);//比较线程ID
pthread_t pthread_self(void);//获得自身线程ID
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void), void *restrict arg);//创建线程(由restrict修饰的指针是最初唯一对指针所指向的对象进行存取的方法,仅当第二个指针基于第一个时,才能对对象进行存取)
进程和线程都会清除其父进程或调用线程的未决信号集。
pag291
如果进程中的
任一线程调用了exit,_exit或者_Exit,那么
整个进程就会终止。
单线程三种不终止整个进程的退出方式:
1、线程只是从启动例程中返回,返回值时线程的退出码。
2、线程可以被同一进程的其他线程取消。
3、线程调用pthread_exit。
int pthread_exit( void *rval_ptr );
int pthread_join( pthread_t thread, void **rval_ptr );
调用pthread_join后,调用进程将一直阻塞,直到指定线程调用pthread_exit、从启动例程中返回或者被取消。
pthread_join无法对分离状态的线程进行操作。(pthread_detach使其分离)
pthread_create和pthread_exit中的无类型指针参数所使用的内存在调用者完成调用后必须仍然有效,否则会出现无效或非法内存访问。( 可以使用全局变量或者在堆上分配动态内存)
如:在调用线程的栈上分配该结构,或者在自己的栈上分配了一个结构然后把指向这个结构够的指针传给pthread_exit,那么当调用pthread_join的线程试图使用该结构时,这个栈有可能已被撤销。
pag295
int pthread_cancel(pthread_t tid);//请求取消同一 进程中的其他线程
不等待线程终止,仅仅提出请求
线程清理函数(进程:atexit):
void pthread_cleanup_push( void (*rtn)(void *), void *arg )
void pthread_cleanup_pop( int execute )
执行以下动作时调用:
1、调用pthread_exit时。
2、响应取消请求时。
3、用非零execute参数调用pthread_cleanup_pop时
( 不包括return!)
因可实现为宏,所以必须在与线程相同的作用域中以匹配对的形式使用。
进程-------------------线程
fork-------------------pthread_create-------------------创建新的控制流
exit-------------------pthread_exit-------------------从现有的控制流中退出
waitpid---------------pthread_join-------------------等待控制流退出并得到退出状态
atexit-----------------pthread_cleanup_push-----------注册在退出控制流时调用的函数
getpid----------------pthread_self-------------------获取控制流的ID
abort-------------------pthread_cancel-------------------请求控制流的非正常退出
int pthread_detach(pthread_t tid);//使线程进入分离状态
在默认情况下,线程终止状态会保存到对该线程调用phtread_join,如果线程已经处于
分离状态,线程的底层存储资源可以在线程终止时
立即被收回。
pag330
线程同步机制:
互斥锁:
使用之前必须初始化(pthread_mutex_init),释放底层内存之前必须销毁(pthread mutex_destroy)
互斥量:
常量PTHREAD_MUTEX_INITIALIZER(只对静态分配的互斥量)
一次只有一个线程可以对其加锁
int pthread_mutex_init( pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr );
int pthread_nutex_destroy( pthread_mutex_t *mutex ) (释放动态分配的互斥量)
int pthread_mutex_lock( pthread_mutex_t *mutex ) (如已锁,调用线程将阻塞到互斥量被解锁)
int pthread_mutex_trylock( pthread_mutex_t *mutex ) (尝试加锁,已加则返回EBUSY)
int pthread_mutex_unlock( pthread_mutex_t *mutex )
读写锁:
三种状态:
1、
写模式加锁状态(一次只有一个线程可以占有写模式的读写锁)
在这个锁被解锁之前,所有试图对这个锁加锁的线程都会被阻塞。
2、
读模式加锁状态(多个线程可以同时占有读模式的读写锁)
所有已读模式对他进行加锁的线程都可以得到访问权,但是如果线程希望以写模式对此锁进行加锁,他必须阻塞到所有的线程释放读锁。
3、
不加锁状态
int pthread_rwlock_init( pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr );
int pthread_rwlock_destroy( pthread_rwlock_t *rwlock )
int pthread_rwlock_rdlock( pthread_rwlock_t *rwlock )
int pthread_rwlock_wrlock( pthread_rwlock_t *rwlock )
int pthread_rwlock_unlock( pthread_rwlock_t *rwlock )
int pthread_rwlock_tryrdlock( pthread_rwlock_t *rwlock )
int pthread_rwlock_trywrlock( pthread_rwlock_t *rwlock )
条件变量:
静态分配的条件变量:PTHREAD_COND_INITIALIZER
条件变量本身是
由互斥量保护的。
int pthread_cond_init( pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr );
int pthread_cond_destroy( pthread_cond_t *cond )
int pthread_cond_wait( pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex )
调用后把调用线程放到等待条件的线程列表上,然后
对互斥量解锁(以便其他线程可以获取资源);
返回时,
互斥量再次被锁住
int pthread_cond_timedwait( pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict timeout )
int pthread_cond_signal( pthread_cond_t *cond )
int pthread_cond_broadcast( pthread_cond_t *cond )
注意:要
在改变条件以后再给线程发送信号(唤醒线程必须重新检查条件,不能仅仅因为pthread_cond_wait 返回就假定条件为真)
条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:
- 一个线程等待"条件变量的条件成立"而挂起;
- 另一个线程使"条件成立"(给出条件成立信号);
为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。