(1)线程清理函数
void pthread_cleanup_push(void (*routine)(void *),void *arg);
void pthread_cleanup_pop(int execute);
(2)线程互斥量
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *attr);
int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
#include<time.h>
struct timespec {
long tv_sec;
long tv_nsec;
};
int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abs_timeout);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
(3)线程读写锁
int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(phtread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
(4)条件变量
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
线程清理:
使用pthread_cleanup_push(void (*routine)(void *),void *arg)和pthread_cleanup_pop(int execute)函数进行注册线程清理函数入栈和出栈,遵循栈空间先进后出的原则;
有三种行为可以触发清理函数的调用:调用pthread_exit函数;相应pthread_cancel响应;用非零的参数调用pthread_cleanup_pop;
当逻辑判断不需要处理清理函数时,只需调用pthread_cleanup_pop(0)会自动清除最顶部的栈空间;
线程互斥量:
可以使用PTHREAD_MUTEX_INITIALIZER为静态变量进行初始化操作或者调用pthread_mutex_init函数;
pthread_mutex_lock会一直阻塞,pthread_mutex_trylock会直接返回,成功返回0,失败返回EBUSY;
如果对一个互斥量加锁两次就会出现死锁现象;pthread_mutex_trylock函数可以避免出现死锁;
当使用两个互斥量时,总是使它们以相同的顺序加锁,避免死锁;
线程读写锁:
读写锁又叫共享-独占锁,加了写锁不允许其它线程读和写,加了读锁,只允许读不允许写;
读写锁操作基本与互斥量一致;
条件变量:
条件变量和互斥量一起使用,在锁定了互斥量之后才能计算条件;
pthread_cond_wait或pthread_cond_timedwait函数会阻塞并解锁互斥量;
pthread_cond_timedwait中的时间参数采用绝对时间;
条件变量只是起阻塞和唤醒线程的作用,具体的判断条件还需用户给出,线程被唤醒后,它将重新检查判断条件是否满足,如果还不满足,一般说来线程应该仍阻塞在这里,被等待被下一次唤醒。这个过程一般用while语句实现。
#include <stdio.h> #include <string.h> #include <unistd.h> #include <pthread.h> #include <sched.h> #include <limits.h> #include <sys/prctl.h> #include <errno.h> /* usr date */ static int usr_date = 0; static pthread_mutex_t rw_mutex; // PTHREAD_MUTEX_INITIALIZE or pthread_mutex_init /* thread cleanup func */ void pthread_cleanup(void *arg) { printf("thread cleanup %s ", (char *)arg); } static void test_write(void *arg) { /* set pthread name */ prctl(PR_SET_NAME, "test_write"); printf("write pthread id:%lu ", pthread_self()); /* push pthread cleanup func */ pthread_cleanup_push(pthread_cleanup, "test_write first"); pthread_cleanup_push(pthread_cleanup, "test_write second"); while(usr_date < 5) { /* lock before writing */ pthread_mutex_lock(&rw_mutex); printf("w:usr_date:%d ", usr_date++); /* unlock after writing */ pthread_mutex_unlock(&rw_mutex); sleep(2); } /* need to cleanup */ if (arg) pthread_exit(0); /* not need to cleanup, pop pthread cleanup func */ pthread_cleanup_pop(0); pthread_cleanup_pop(0); pthread_exit(0); return ; } static void test_read(void *arg) { int ret = 0; /* set pthread name */ prctl(PR_SET_NAME, "test_read"); printf("read pthread id:%lu ", pthread_self()); /* push pthread cleanup func */ pthread_cleanup_push(pthread_cleanup, "test_read first"); pthread_cleanup_push(pthread_cleanup, "test_read second"); while(1) { /* lock before reading */ ret = pthread_mutex_trylock(&rw_mutex); if (ret == EBUSY) { printf("trylock is busy "); usleep(200 * 1000); continue; } printf("r:usr_date:%d ", usr_date); /* unlock after reading */ pthread_mutex_unlock(&rw_mutex); sleep(1); } /* not need to cleanup, pop pthread cleanup func */ pthread_cleanup_pop(0); pthread_cleanup_pop(0); pthread_exit(0); return ; } int pthread_set_attr(pthread_attr_t *attr, int priority, size_t stacksize) { int rval; struct sched_param params; int maxPriority, minPriority; rval = pthread_attr_init(attr); if (rval != 0) { return rval; } /* normally, need not to set */ rval = pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED); if (rval != 0) { printf("pthread_attr_setinheritsched failed "); return rval; } rval = pthread_attr_setscope(attr, PTHREAD_SCOPE_SYSTEM); if (rval != 0) { if (rval == ENOTSUP) { printf("The system does not support the %s scope, using %s ", "PTHREAD_SCOPE_SYSTEM", "PTHREAD_SCOPE_PROCESS"); rval = pthread_attr_setscope(attr, PTHREAD_SCOPE_PROCESS); } if (rval) { printf("pthread_attr_setscope failed "); return rval; } } /* use the round robin scheduling algorithm */ rval = pthread_attr_setschedpolicy(attr, SCHED_RR); if (rval != 0) { printf("pthread_attr_setschedpolicy failed "); return rval; } /* set the thread to be detached */ rval = pthread_attr_setdetachstate(attr, PTHREAD_CREATE_JOINABLE); if (rval != 0) { printf("pthread_attr_setdetachstate failed "); return rval; } /* first get the scheduling parameter, then set the new priority */ rval = pthread_attr_getschedparam(attr, ¶ms); if (rval != 0) { printf("pthread_attr_getschedparam failed "); return rval; } minPriority = sched_get_priority_min(SCHED_RR); maxPriority = sched_get_priority_max(SCHED_RR); printf("maxPriority:%d, minPriority:%d ", maxPriority, minPriority); if (priority < minPriority) { priority = minPriority; } else if (priority > maxPriority) { priority = maxPriority; } params.sched_priority = priority; rval = pthread_attr_setschedparam(attr, ¶ms); if (rval != 0) { printf("pthread_attr_setschedparam failed "); return rval; } /* when set stack size, we define a minmum value to avoid fail */ printf("PTHREAD_STACK_MIN:%x ", PTHREAD_STACK_MIN); if (stacksize < PTHREAD_STACK_MIN) { stacksize = PTHREAD_STACK_MIN; } rval = pthread_attr_setstacksize(attr, stacksize); if (rval != 0) { printf("pthread_attr_setstacksize failed "); return rval; } return 0; } void test(void) { pthread_t wtest_taskid; pthread_t rtest_taskid; pthread_attr_t attr; int *retval = NULL; size_t stacksize; int priority; int ret; /* init pthread attr */ pthread_attr_init(&attr); stacksize = 4096; priority = 50; ret = pthread_set_attr(&attr, priority, stacksize); if (ret) { pthread_attr_destroy(&attr); return ; } /* init pthread mutex */ pthread_mutex_init(&rw_mutex, NULL); /* create write pthread */ ret = pthread_create(&wtest_taskid, NULL, (void *)test_write, NULL); if (ret) { printf("%s failed, errno:%d ", __FUNCTION__, errno); } /* create read pthreadi */ ret = pthread_create(&rtest_taskid, NULL, (void *)test_read, NULL); if (ret) { printf("%s failed, errno:%d ", __FUNCTION__, errno); } pthread_attr_destroy(&attr); ret = pthread_join(wtest_taskid, (void **)&retval); printf("%d %d ", ret, (int)retval); if (ret == 0 && (int)retval == 0) { if (pthread_kill(rtest_taskid, 0) == 0) pthread_cancel(rtest_taskid); } /* destrong pthread mutex */ pthread_mutex_destroy(&rw_mutex); printf("pthread exit success! "); } int main(int argc, char **argv) { test(); pause(); return 0; }