API:
pthread_t:
// Are two threads equal?
// Non-zero for 'equal' and zero for 'not equal'.
// Since the posix thread apis have different implementations,
// the type of pthread_t can be int, unsigned long or struct,
// so we should use this function instead of "==".
int pthread_equal(pthread_t t1, pthread_t t2);
// Create a thread.
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*entry_func)(void*),
void *arg);
// Ge handle of current thread
pthread_t pthread_self(void);
// Terminate the current thread which called this function.
// and return a value of any type as the return value of thread.
// Just terminate thread, not collect resource. The resource
// will be collected when the thread is detach or joined.
int pthread_exit(void *threadRetVal);
// When a detached thread terminates,
// its resources are automatically released back to the system
// without the need for another thread to join with the terminated thread.
// Any thread(include itself) could detach the thread by ID.
// Attempting to detach an already detached thread results in unspecified behavior.
// Once a thread has been detached, it can't be joined or be made joinable again.
int pthread_detach(pthread_t thread);
// Block until the indicated thread(parameter) is finished.
// The threadRetVal is the return-value of the joined thread start function,
// and also could be set by pthread_exit.
// After this function returns, the thread could not be joined again.
// thread must be joinable.
// Joining with a thread that has previously been joined results in undefined behavior.
int pthread_join(pthread_t thread, void **threadRetVal);
pthread_mutext_t:
PTHREAD_MUTEX_NORMAL,PTHREAD_MUTEX_ERRORCHECK,PTHREAD_MUTEX_RECURSIVE
数据本身不能直接拷贝(结果未定义),可拷贝指针共享该互斥量;
推荐使用全局互斥量,可static,也可extern;
使用PTHREAD_MUTEX_INITIALIZER声明静态的默认属性mutex;
防止多互斥量产生死锁的方式:1.规定加锁顺序(并反向解锁),2.使用trylock,在失败时释放已获得的其余锁
解锁不会导致死锁发生
// Initialize a mutex with an attribute.
int pthread_mutex_init(pthread_mutext_t *mutex, pthread_mutexattr_t *attr);
// Destory a mutex through the pointer.
int pthread_mutex_destory(pthread_mutex_t *mutex);
// Lock the mutex.
// If it has been locked already in other thread,
// it will be blocked until the mutex is unlocked.
// If it has been locked in current, then it is unspecified behavior.
// Return error code with 0, EINVAL(invalid mutex), EAGAIN or EDEADLK(twice lock).
int pthread_mutex_lock(pthread_mutex_t *mutex);
// Like pthread_mutex_lock, but it will just try to lock the mutex,
// If not success, then return EBUSY immediately(non-block).
// If success, then lock the mutex and return 0.
// Often, need if-else code to deal with the case for trylock-failed.
int pthread_mutex_trylock(pthread_mutex_t *mutex);
// Unlock the mutex.
// If the mutex is not locked, this is unspecified behavior.
// Unlock the mutex which has been locked by another thread is unspecified behavior.
int pthread_mutex_unlock(pthread_mutex_t *mutex);
// Initialize a condition variable with indicated attribute.
pthread_cond_t:
1、不可以直接拷贝,可拷贝指针共享该变量
2、不单独使用,而与互斥量一起使用,所有使用cond的线程都必须使用相同的mutex加锁。
3、可用PTHREAD_COND_INITIALIZER声明静态条件变量,且
不需要手动释放它
4、可用init函数动态初始化,但要保证该变量
仅初始化一次,或者用pthread_once来保证
5、使用非默认attribute的条件变量则必须使用init函数,而不能静态初始化
6、pthread_cond_wait()用于阻塞当前线程,且
必须在mutex的lock和unlock之间
7、pthread_cond_wait()函数调用时会马上
unlock,唤醒返回时,该线程又自动
lock该mutex 。
8、pthread_cond_signals()
且必须在mutex的lock和unlock之间,且不管有没有等待的线程,都成功返回。
9、无论如何一个pthread_cond_signal调用最多发信一次,或者不发送(无线程等待cond)。
10、pthread_cond_broadcast()向所有等待指定信号的线程发送信号,等待的线程按优先级被唤醒。
Waiting until x is greater than y:
pthread_mutex_lock(&mut);
while (x <= y) { // 总在循环中wait,从而达到wait之前和之后测试condition的目的。
pthread_cond_wait(&cond, &mut);
}
/* operate on x and y */
pthread_mutex_unlock(&mut);
Modifications on x and y that may cause x to become greater than y should signal the condition if needed:
pthread_mutex_lock(&mut);
/* modify x and y */
if (x > y) pthread_cond_signal(&cond);
pthread_mutex_unlock(&mut);
// Initialize the condition variable with mutex.
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *condattr);
// Destory a condition variable
int pthread_cond_destory(pthread_cond_t *cond);
// Wait for a condition
// Must be in the block of 'mutex lock' and 'mutex unlock'
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mut);
// If did not wait till time out, then return ETIMEOUT
// Must be in the block of 'mutex lock' and 'mutex unlock'
int pthread_cond_timedwait(pthread_cond_t *cond,
pthread_mutex_t *mutex,
struct timespec *expiration);
// Wake up a thread which is waiting the condition.
// Must be in the block of 'mutex lock' and 'mutex unlock'
int pthread_cond_signals(pthread_cond_t *cond);
// Wake up threads which are waiting the condition.
// Must be in the block of 'mutex lock' and 'mutex unlock'
int pthread_cond_broadcast(pthread_cond_t *cond);
pthread_once_t:
pthread_once_t
int pthread_once(pthread_once_t *once, void (*once_routine)(void);
DataType:
pthread_key_t:
pthread_attr_t:线程属性
pthread_mutexattr_t:互斥量属性
pthread_condattr_t:条件变量属性
生命周期
创建线程:
一般是通过pthread_create来创建;
由于线程调度机制的影响,新创建的线程可能马上执行,也可能等待一段时间才执行;
pthread_create返回和被创建线程的执行不存在同步关系,
可能在没返回之前就已经开始执行,也可能已经执行完毕。
启动线程:
除主线程以外的所有线程start函数都包含一个void*类型的参数;
主线程main函数不同,并且当main函数返回时,进程中的所有线程都将终止;
若想主线程结束但不终止进程中其他线程,则需要调用pthread_exit;
主线程的堆栈一般没有具体限制,但普通线程可能有限制。
运行和阻塞:
分配到CPU时间片且资源足够则运行;
没有时间片则转为就绪;
没有资源则转为阻塞;
阻塞时获得足够资源则转为就绪。
终止:
线程正常返回时,进入终止状态;
调用pthread_exit和pthread_cancel时,清理(不是回收)线程结束后进入终止状态;
若线程是detached,则终止后被系统回收资源;
若线程是joined,则线程执行完毕后pthread_join返回,
但是资源回收可能会先于返回操作,所以线程的返回值一定不要是该线程堆栈上的数据;
ps:也可以不用join操作来获得返回的数据,而将数据保存在一个全局的地方。
回收:
如果设置线程的属性是PTHREAD_CREATE_DETACH来建立的线程,
或者调用pthread_detach来分离线程的话,则线程结束自动回收;
如果线程没被分离过,则结束后需要等待join或者detach进行资源回收;
注意:一旦线程被回收,则不应该再继续引用threadID;
此外,资源的回收指的是对于系统资源进行回收,而线程执行过程中的进程资源并不包含在内,
所以线程退出前需要手动归还malloc/mutex等资源。
![](https://app.yinxiang.com/shard/s1/res/5e43920f-f71c-46a8-8885-96d0f23e3bf0/ThreadState.png?resizeSmall&width=1066)
fork():从当前进程复制一个相同的子进程,然后二者同时执行后续代码。函数在父进程中返回创建的子进程的pid,函数在子进程中返回0,二者共享代码,但拥有独立的数据。若父进程退出,则子进程的ppid更改为进程号1。
getpid():获取当前进程ID
getppid():获取当前进程的父进程ID