zoukankan      html  css  js  c++  java
  • 线程相关操作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;
    }
    

      

  • 相关阅读:
    NHibernate中的Clear和Flush方法
    什么是POCO类
    node-vuecli 脚手架安装
    layui表单引入ueditor遇坑记
    PHP的九个超全局变量
    PHP的八个魔术常量
    PHP的七个数组指针函数
    TP6.0多应用模式隐藏路由中的应用名
    TP6.0中的密码验证逻辑、验证器的使用
    Vue 侦听器 watch
  • 原文地址:https://www.cnblogs.com/hancq/p/5408352.html
Copyright © 2011-2022 走看看