线程是允许应用程序并发执行多个任务的一种机制;一个进程可以包含多个线程,统一程序中的线程会独立执行相同的程序,且共享同一份全局内存区域。
Posix统一了Pthreads线程接口的标准,提供了一套跨平台的线程创建、同步和管理API。
Pthread常用数据类型:
程序启动运行时只有一条主线程(main
函数),可以使用pthread_creat()
函数来创建新的子线程:
#include
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start)(void *), void *arg);
/*return 0 on success,or a positive errno on error*/
arg
的函数start
开始执行,新建的线程执行start
函数里面的内容,调用pthread_create()
的线程会继续执行后面的内容。arg
为void *
类型,可以将指向任意对象的指针传递给start
函数,需要传递多个参数时,可以将arg
指向一个结构体thread
指向pthread_t
类型的缓冲区,在pthread_creat()
返回之前,会在此保存该线程的唯一标识(ID),后续的pthread函数可以通过该表示来引用此线程终止线程有很多方式:
start
执行return
语句并返回值之后线程终止pthread_exit()
和pthread_cancle()
函数取消线程exit()
,或者主线程执行了return
语句pthread_exit终止线程:
#include
void pthread_exit(void *retval);
pthread_exit()
来退出线程,与return
功能相似retval
中保存了线程的返回值,其所指向的内容不应该分配在线程栈中pthread_exit()
后,其他线程还会继续执行进程内部的每个线程都有唯一的标识,称为线程ID。在Linux中:
获取自己线程的ID:
#include
pthread_t pthread_self(void);
检查两个线程的ID是否相同:
#include
int pthread_equal(pthread_t t1, pthread_t t2);
/*return nonezero value if t1 equal to t2, otherwise 0*/
pthread_join()
等待由thread
标识的线程终止,如果线程已经终止则会立即返回 #include
int pthread_join(pthread_t thread, void **retval);
/*return 0 on success or a positive error number on error*/
thread
指定了需要连接的线程retval
为一非空指针,用于保存线程终止时返回值的拷贝(即线程return
值或调用pthread_exit()
所指定的值)waitpid()
类似,但线程之间的关系是对等的,进程中的任意线程均可以通过该函数与进程中的任意线程建立连接 /* Thread handler function for pthread_create */
void* handle_create(void *arg){
pthread_t tid = pthread_self();
printf("I am thread %ld\n",(long int)tid);
/* Check if argument is NULL */
char *str = (char*)arg;
if(str == NULL){
printf("nothing recived form str\n");
pthread_exit((void*)-1);
}
/* Print received message */
printf("message form pthread_create:\n%s\n",str);
return (void*)0;
}
/* Main function to demonstrate thread creation and joining */
int thread_pthread_func(int argc, char *argv[]){
/* Check command line arguments */
if(argc < 2){
printf("Usage:%s \n" , argv[0]);
return -1;
}
/* Handle NULL argument case */
char *str = (strcmp(argv[1],"NULL") == 0) ? NULL : argv[1];
/* Create new thread */
pthread_t pth;
int err = pthread_create(&pth, NULL, handle_create, str);
if(err != 0){
printf("pthread_create error:%s\n", strerror(err));
return -1;
}
/* Wait for thread to complete and get return value */
void *ret = NULL ;
int join = pthread_join(pth, &ret);
if(join != 0){
printf("pthread_join error: %s\n", strerror(join));
return -1;
}
printf("thread %ld exit status: %ld\n", (long int)pth, (intptr_t)ret);
return 0;
}
针对共享资源锁定互斥量 --> 访问共享资源 --> 解锁互斥量
pthread_mutex_t
类型的变量,使用前必须对其进行初始化,初始化后的互斥量处于解锁状态 pthrea_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
mutex
是需要解锁或锁定的互斥量 #include
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
/*return 0 on success or a positive error number on error*/
pthread_mutex_lock()
锁定互斥量时,若互斥量处于未锁定状态,则函数锁定该互斥量并立即返回;若互斥量处于锁定状态,则一直阻塞,当互斥量解锁时锁定互斥量并返回pthread_mutex_unlock()
解锁互斥量时,不能对处于未锁定状态的互斥量进行解锁,不能解锁其他线程锁定的互斥量 /* Shared data protected by mutex */
static long int data_mutex;
/* Mutex for protecting data_mutex */
static pthread_mutex_t mtx_lock_unlock = PTHREAD_MUTEX_INITIALIZER;
/* Thread function that increments shared data with mutex protection */
void *handler_mutex_lock_unlock(void *num){
/* Convert argument to loop count */
int loop = atoi((char*)num);
int ret, tmp;
/* Loop to increment shared data */
for(int i = 0; i < loop; i++){
/* Lock mutex before accessing shared data */
ret = pthread_mutex_lock(&mtx_lock_unlock);
if(ret != 0){
printf("pthread_mutex_lock error :%s\n",strerror(ret));
return (void*)-1;
}
/* Critical section: increment shared data */
tmp = data_mutex;
tmp++;
data_mutex = tmp;
/* Unlock mutex after accessing shared data */
ret = pthread_mutex_unlock(&mtx_lock_unlock);
if(ret != 0){
printf("pthread_mutex_unlock error:%s\n", strerror(ret));
return (void*)-1;
}
}
return (void*)0;
}
/* Function to create multiple threads that increment shared data */
int main(int argc, char *argv[]){
/* Check command line arguments */
if(argc < 2 || atoi(argv[1]) < 0){
printf("Usage:%s " , argv[0]);
return -1;
}
/* Create 5 threads */
pthread_t thr[5];
int errn;
for(int i = 0; i < 5; i++){
errn = pthread_create(&thr[i], NULL, handler_mutex_lock_unlock, (void*)argv[1]);
if(errn != 0){
printf("pthread_create error:%s\n", strerror(errn));
return -1;
}
}
/* Wait for all threads to complete */
void *ret = NULL;
for(int j = 0; j < 5; j++){
if(pthread_join(thr[j], &ret) != 0){
printf("pthread_join error\n");
return -1;
}
if((intptr_t)ret != 0)
printf("thread %ld exit error\n", (long int)thr[j]);
}
/* Print final value of shared data */
printf("the value of \"data_mutex\" is %ld \n", data_mutex);
return 0;
}
(1)固定加锁顺序:所有线程按照相同的顺序获取锁
(2)使用尝试加锁:pthread_mutex_trylock()
避免阻塞
(3)设置超时机制:pthread_mutex_timedlock()
限制等待时间
(4)避免嵌套锁:尽量减少同时持有多个锁的情况
(5)使用锁层次结构:为锁定义层次关系,只允许按层次获取
(1)PTHREAD_MUTEX_NORMAL
:标准互斥量,不检测死锁和重复加锁
(2)PTHREAD_MUTEX_ERRORCHECK
:错误检查互斥量,检测死锁和重复加锁并返回错误
(3)PTHREAD_MUTEX_RECURSIVE
:递归互斥量,允许同一线程多次加锁
(4)PTHREAD_MUTEX_DEFAULT
:默认类型,通常映射为NORMAL或ERRORCHECK
pthread_mutexattr_settype()
设置: #include
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);
/*return 0 on success or a positive error number on error*/
pthread_mutex_t mutex;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&mutex, &attr);
pthread_mutexattr_destroy(&attr);
PTHREAD_MUTEX_INITIALIZER
只能用于对静态分配且拥有默认属性的互斥量进行初始化 #include
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
int pthread_mutex_destory(pthread_mutex_t *mutex);
/*return 0 on success or a positive error number on error*/
mutex
是需要初始化或者销毁的互斥量,attr
用于定义互斥量的属性,为NULL表示默认属性 /*mutex to protect shared data*/
static pthread_mutex_t mtx_mutex_init;
/* Shared data protected by mutex */
static long int data_mutex_init = 0;
void *handler_mutex_init(){
// Lock mutex before accessing shared data
int ret = pthread_mutex_lock(&mtx_mutex_init);
if(ret != 0){
printf("pthread_lock error :%s\n", strerror(ret));
return (void*)-1;
}
// Critical section: increment shared data
long int tmp = data_mutex_init;
for(int i = 0; i < 100000; i++)
tmp ++;
data_mutex_init = tmp;
// Unlock mutex after accessing shared data
ret = pthread_mutex_unlock(&mtx_mutex_init);
if(ret != 0){
printf("pthread_unlock error :%s\n", strerror(ret));
return (void*)-1;
}
return (void*)0;
}
int thread_mutex_init(){
// Initialize mutex
int ret = pthread_mutex_init(&mtx_mutex_init, NULL);
if(ret != 0){
printf("pthread_mutex_init error: %s\n", strerror(ret));
return -1;
}
// Create first thread
pthread_t pth_1, pth_2;
ret = pthread_create(&pth_1, NULL, handler_mutex_init, NULL);
if(ret != 0){
printf("pthread_create error:%s\n", strerror(ret));
return -1;
}
// Create second thread
ret = pthread_create(&pth_2, NULL, handler_mutex_init, NULL);
if(ret != 0){
printf("pthread_create error:%s\n", strerror(ret));
goto clean_up;
}
// Wait for threads to complete and check their status
void *err;
if(pthread_join(pth_1, &err) != 0){
printf("pthread_join error\n");
goto clean_up;
}
if((intptr_t)err != 0)
printf("thread %ld exit error\n", (long int)err);
if(pthread_join(pth_2, &err) != 0){
printf("pthread_join error\n");
goto clean_up;
}
if((intptr_t)err != 0)
printf("thread %ld exit error\n", (long int)err);
clean_up:
// Clean up mutex resources
if(pthread_mutex_destroy(&mtx_mutex_init) != 0){
printf("pthread_mutes_destory error\n");
return -1;
}
// Print final value of shared data
printf("the value of data_mutex_init is %ld\n", data_mutex_init);
return 0;
}
pthread_cond_wait()
:等待条件变量pthread_cond_signal()
:唤醒一个等待线程pthread_cond_broadcast()
:唤醒所有等待线程PTHREAD_COND_INITIALIZER
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
#include
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
int pthread_cond_destroy(pthread_cond_t *cond);
/*return 0 on success or error number on failure*/
attr
指定了条件变量的属性,若为NULL则表示默认属性 pthread_cond_t cond;
pthread_cond_init(&cond, NULL);
/*...*/
pthread_cond_destroy(&cond);
#include
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
/*return 0 on success or error number on failure*/
cond
是指向条件变量的指针,参数mutex
是指向与条件变量配合使用的互斥量的指针pthread_cond_signal()
只会唤醒一条处于等待状态的线程,只有一条需要唤醒的线程时推荐使用pthread_cond_broadcast()
会唤醒所有处于等待状态的线程,有多条线程等待时推荐使用pthread_cond_wait()
的执行过程:(1)解锁互斥量
(2)使调用线程进入等待状态(阻塞)
(3)当被其他线程通过signal/broadcast唤醒时,重新获取互斥锁
(4)只有成功获取互斥锁后,函数才会返回
/* Mutex for producer-consumer synchronization */
pthread_mutex_t mtx_cp = PTHREAD_MUTEX_INITIALIZER;
/* Condition variable for producer-consumer synchronization */
pthread_cond_t con_cp = PTHREAD_COND_INITIALIZER;
/* Count of available products */
static int available = 0;
/* Count of consumed products */
static int consumed = 0;
/* Producer thread function that creates products */
void *handler_productor(){
sleep(1);
/* Lock mutex before accessing shared data */
int err = pthread_mutex_lock(&mtx_cp);
if(err != 0){
printf("mutex lock error: %s\n", strerror(err));
return (void*)-1;
}
/* Increment available products count */
available++;
printf("one product produced, we will inform the consumer\n");
/* Signal consumer that product is available */
err = pthread_cond_signal(&con_cp);
if(err != 0){
printf("cont signal error: %s\n", strerror(err));
pthread_mutex_unlock(&mtx_cp);
return (void*)-1;
}
/* Unlock mutex after accessing shared data */
err = pthread_mutex_unlock(&mtx_cp);
if(err != 0){
printf("mutex unlock error: %s\n", strerror(err));
return (void*)-1;
}
return (void*)0;
}
/* Consumer thread function that consumes products */
void *handler_consumer(){
/* Lock mutex before checking shared data */
int err = pthread_mutex_lock(&mtx_cp);
if(err != 0){
printf("mutex lock error:%s\n", strerror(err));
return (void*)-1;
}
/* Wait while no products are available */
while(available <= 0){
err = pthread_cond_wait(&con_cp, &mtx_cp);
if(err != 0){
printf("cont wait error:%s\n", strerror(err));
pthread_mutex_unlock(&mtx_cp);
return (void*)-1;
}
}
/* Consume product and update counters */
available--;
consumed++;
printf("one product has benn consumed\n");
/* Unlock mutex after accessing shared data */
err = pthread_mutex_unlock(&mtx_cp);
if(err != 0){
printf("mutex unlock error:%s\n", strerror(err));
return (void*)-1;
}
return (void*)0;
}
/* Main function for producer-consumer demonstration */
int thread_producter_consumer(int argc, char *argv[]){
/* Check command line arguments */
if(argc < 2 || atoi(argv[1]) <= 0){
printf("Usage:%s \n" , argv[0]);
return -1;
}
int err, tmp = atoi(argv[1]);
/* Create producer and consumer threads */
pthread_t pth_p[tmp],pth_c[tmp];
for(int i = 0; i < tmp; i++){
err = pthread_create(&pth_p[i], NULL, handler_productor, NULL);
if(err != 0){
printf("thread created error:%s\n", strerror(err));
return -1;
}
err = pthread_create(&pth_c[i], NULL, handler_consumer, NULL);
if(err != 0){
printf("thread created error:%s\n", strerror(err));
return -1;
}
}
/* Wait for all threads to complete */
for(int i = 0; i < tmp; i++){
pthread_join(pth_p[i], NULL);
pthread_join(pth_c[i], NULL);
}
/* Print total consumed products */
printf("the consumer has totally consumed %d producteds\n", consumed);
return 0;
}
printf("thread created error:%s\n", strerror(err));
return -1;
}
err = pthread_create(&pth_c[i], NULL, handler_consumer, NULL);
if(err != 0){
printf("thread created error:%s\n", strerror(err));
return -1;
}
}
/* Wait for all threads to complete */
for(int i = 0; i < tmp; i++){
pthread_join(pth_p[i], NULL);
pthread_join(pth_c[i], NULL);
}
/* Print total consumed products */
printf("the consumer has totally consumed %d producteds\n", consumed);
return 0;
}