(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;
}