线程相关操作2-线程同步

(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_destroy(pthread_mutex_t *mutex);

int pthread_mutex_lock(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_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); 
 
线程清理:
    使用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, &params);
    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, &params);
    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;
}

  

原文地址:https://www.cnblogs.com/hancq/p/5408352.html