• 读写锁和互斥量(互斥)很类似,是另一种线程同步机制,但属于POSIX标准,可以用来同步同一进程中的各个线程。当然如果一个读写锁存放在多个进程共享的某个内存区中,那么还可以用来进行进程间的同步, 和...

    读写锁和互斥量(互斥锁)很类似,是另一种线程同步机制,但不属于POSIX标准,可以用来同步同一进程中的各个线程。当然如果一个读写锁存放在多个进程共享的某个内存区中,那么还可以用来进行进程间的同步,

    和互斥量不同的是:互斥量会把试图进入已保护的临界区的线程都阻塞;然而读写锁会视当前进入临界区的线程和请求进入临界区的线程的属性来判断是否允许线程进入。

    相对互斥量只有加锁和不加锁两种状态,读写锁有三种状态:读模式下的加锁,写模式下的加锁,不加锁

    读写锁的使用规则:

    • 只要没有写模式下的加锁,任意线程都可以进行读模式下的加锁;
    • 只有读写锁处于不加锁状态时,才能进行写模式下的加锁;

    读写锁也称为共享-独占(shared-exclusive)锁,当读写锁以读模式加锁时,它是以共享模式锁住,当以写模式加锁时,它是以独占模式锁住。读写锁非常适合读数据的频率远大于写数据的频率从的应用中。这样可以在任何时刻运行多个读线程并发的执行,给程序带来了更高的并发度。

    需要提到的是:读写锁到目前为止仍然不是属于POSIX标准,本文讨论的读写锁函数都是有Open Group定义的的。例如下面是在我机器上,编译器是gcc version 4.4.6,关于读写锁的定义是包含在预处理命令中的:

    1. #if defined __USE_UNIX98 || defined __USE_XOPEN2K  
    2.   
    3. ... 读写锁相关函数声明...  
    4.   
    5. #endif  

    1读写锁的初始化和销毁

    1. /* Initialize read-write lock  */  
    2.  int pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock,  
    3.                                 __const pthread_rwlockattr_t *__restrict __attr);  
    4.   
    5. /* Destroy read-write lock */  
    6. extern int pthread_rwlock_destroy (pthread_rwlock_t *__rwlock);  
    7.   
    8.                                                返回值:成功返回0,否则返回错误代码  

    上面两个函数分别由于读写锁的初始化和销毁。和互斥量,条件变量一样,如果读写锁是静态分配的,可以通过常量进行初始化,如下:

    1. pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;  

    也可以通过pthread_rwlock_init()进行初始化。对于动态分配的读写锁由于不能直接赋值进行初始化,只能通过这种方式进行初始化。pthread_rwlock_init()第二个参数是读写锁的属性,如果采用默认属性,可以传入空指针NULL

    那么当不在需要使用时及释放(自动或者手动)读写锁占用的内存之前,需要调用pthread_rwlock_destroy()进行销毁读写锁占用的资源。

    2读写锁的属性设置

    1. /* 初始化读写锁属性对象 */  
    2. int pthread_rwlockattr_init (pthread_rwlockattr_t *__attr);  
    3.   
    4. /* 销毁读写锁属性对象 */  
    5. int pthread_rwlockattr_destroy (pthread_rwlockattr_t *__attr);  
    6.   
    7. /* 获取读写锁属性对象在进程间共享与否的标识*/  
    8. int pthread_rwlockattr_getpshared (__const pthread_rwlockattr_t * __restrict __attr,  
    9.                                           int *__restrict __pshared);  
    10.   
    11. /* 设置读写锁属性对象,标识在进程间共享与否  */  
    12. int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *__attr, int __pshared);  
    13.   
    14.                                                     返回值:成功返回0,否则返回错误代码  
    这个属性设置和互斥量的基本一样,具体可以参考互斥量的设


    3读写锁的使用

    1. /* 读模式下加锁  */  
    2. int pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock);  
    3.   
    4. /* 非阻塞的读模式下加锁  */  
    5. int pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock);  
    6.   
    7. # ifdef __USE_XOPEN2K  
    8. /*  限时等待的读模式加锁 */  
    9. int pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock,  
    10.                                        __const struct timespec *__restrict __abstime);  
    11. # endif  
    12.   
    13. /* 写模式下加锁  */  
    14. int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock);  
    15.   
    16. /* 非阻塞的写模式下加锁 */  
    17. int pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock);  
    18.   
    19. # ifdef __USE_XOPEN2K  
    20. /* 限时等待的写模式加锁 */  
    21. int pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock,  
    22.                                        __const struct timespec *__restrict __abstime);  
    23. # endif  
    24.   
    25. /* 解锁 */  
    26. int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock);  
    27.   
    28.                                                    返回值:成功返回0,否则返回错误代码  

    1pthread_rwlock_rdlock()系列函数

    pthread_rwlock_rdlock()用于以读模式即共享模式获取读写锁,如果读写锁已经被某个线程以写模式占用,那么调用线程就被阻塞。在实现读写锁的时候可以对共享模式下锁的数量进行限制(目前不知如何限制)。

    pthread_rwlock_tryrdlock()pthread_rwlock_rdlock()的唯一区别就是,在无法获取读写锁的时候,调用线程不会阻塞,会立即返回,并返回错误代码EBUSY

    pthread_rwlock_timedrdlock()是限时等待读模式加锁,时间参数struct timespec * __restrict __abstime也是绝对时间,和条件变量的pthread_cond_timedwait()使用基本一致,具体可以参考pthread_cond_timedwait() 

    2pthread_rwlock_wrlock()系列函数

    pthread_rwlock_wrlock()用于写模式即独占模式获取读写锁,如果读写锁已经被其他线程占用,不论是以共享模式还是独占模式占用,调用线程都会进入阻塞状态。

    pthread_rwlock_trywrlock()在无法获取读写锁的时候,调用线程不会进入睡眠,会立即返回,并返回错误代码EBUSY

    pthread_rwlock_timedwrlock()是限时等待写模式加锁,也和条件变量的pthread_cond_timedwait()使用基本一致,具体可以参考pthread_cond_timedwait()

    3pthread_rwlock_unlock()

    无论以共享模式还是独占模式获得的读写锁,都可以通过调用pthread_rwlock_unlock()函数进行释放该读写锁。


    测试代码;

    /*
     * pthread_rdlock.c
     *
     */
    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    #include <unistd.h>
    
    struct share{
    	pthread_rwlock_t rwlock;
    	int product;
    };	//把共享数据和它们的同步变量集合到一个结构中,这往往是一个较好的编程技巧。
    
    struct share *shareData;
    void *produce(void *);
    void *consume1(void *);
    void *consume2(void *);
    
    int main(void)
    {
    	pthread_t pid,cid1,cid2;
    	int res;
    	void *ret;
    
    	srand(time(NULL));
    	shareData = malloc(sizeof(struct share));
    	if(shareData == NULL)
    	{
    		perror("shareData malloc fail");
    		exit(1);
    	}
    	res = pthread_rwlock_init(&shareData->rwlock,NULL);
    	if(res != 0)
    	{
    		perror("rwlock init fail");
    		exit(1);
    	}
    	res = pthread_create(&pid,NULL,produce,NULL);
    	if(res != 0)
    	{
    		perror("pthread produce create fail");
    		exit(1);
    	}
    	res = pthread_create(&cid1,NULL,consume1,NULL);
    	if(res != 0)
    	{
    		perror("pthread consume1 create fail");
    		exit(1);
    	}
    	res = pthread_create(&cid2,NULL,consume2,NULL);
    	if(res != 0)
    	{
    		perror("pthread consume2 create fail");
    		exit(1);
    	}
    
    	res = pthread_join(pid,&ret);
    	if(res == 0)
    		printf("producer exit\n");
    	res = pthread_join(cid1,&ret);
    	if(res == 0)
    		printf("consumer1 exit\n");
    	res = pthread_join(cid2,&ret);
    	if(res == 0)
    		printf("consumer2 exit\n");
    	pthread_rwlock_destroy(&shareData->rwlock);
    	exit(0);
    }
    
    void *produce(void *arg)
    {
    	int i;
    	for(i=0;i<6;i++)
    	{
    		pthread_rwlock_wrlock(&shareData->rwlock);
    		shareData->product = rand()%100+1;
    		printf("produce:%d\n",shareData->product);
    		pthread_rwlock_unlock(&shareData->rwlock);
    		sleep(1);
    	}
    	pthread_exit(NULL);
    }
    
    void *consume1(void *arg)
    {
    	int i;
    	for(i=0;i<6;i++)
    	{
    		pthread_rwlock_rdlock(&shareData->rwlock);
    		printf("consume1:%d\n",shareData->product);
    		pthread_rwlock_unlock(&shareData->rwlock);
    		sleep(1);
    	}
    	pthread_exit(NULL);
    }
    
    void *consume2(void *arg)
    {
    	int i;
    	for(i=0;i<6;i++)
    	{
    		pthread_rwlock_rdlock(&shareData->rwlock);
    		printf("consume2:%d\n",shareData->product);
    		pthread_rwlock_unlock(&shareData->rwlock);
    		sleep(1);
    	}
    	pthread_exit(NULL);
    }
    

    运行结果:

    consume2:0
    consume1:0
    produce:10
    consume1:10
    consume2:10
    produce:23
    consume1:23
    consume2:23
    produce:4
    consume2:4
    consume1:4
    produce:55
    consume1:55
    consume2:55
    produce:87
    consume2:87
    consume1:87
    produce:63
    producer exit
    consumer1 exit
    consumer2 exit

    注意:如果要实现生产-消费者模型,则消费者线程还应该加上条件变量,当共享区域没有数据时,阻塞等待。


    如果把consume1的解锁注释掉,如下:

    void *consume1(void *arg)
    {
    	int i;
    	for(i=0;i<6;i++)
    	{
    		pthread_rwlock_rdlock(&shareData->rwlock);
    		printf("consume1:%d\n",shareData->product);
    		//pthread_rwlock_unlock(&shareData->rwlock);
    		sleep(1);
    	}
    	pthread_exit(NULL);
    }
    运行结果:

    consume2:0
    consume1:0
    consume2:0
    consume1:0
    consume1:0
    consume2:0
    consume2:0
    consume1:0
    consume1:0
    consume2:0
    consume2:0
    consume1:0


    可以看出,当生产者线程试图以写模式加锁时,由于consume1没有释放读锁,所以会一直阻塞;而consume2以读模式则依然可以成功加锁。

    展开全文
  • linux读写锁

    2018-05-22 13:29:39
    一、读写锁是什么? 读写锁其实还是一种,是给一段临界区代码加锁,但是此加锁是在进行写操作的时候才会互斥,而在进行读的时候是可以共享的进行访问临界区的 ps:读写锁本质上是一种自旋 二、为什么...

    一、读写锁是什么?

    读写锁其实还是一种锁,是给一段临界区代码加锁,但是此加锁是在进行写操作的时候才会互斥,而在进行读的时候是可以共享的进行访问临界区的
    ps:读写锁本质上是一种自旋锁

    二、为什么需要读写锁?

    有时候,在多线程中,有一些公共数据修改的机会比较少,而读的机会却是非常多的,此公共数据的操作基本都是读,如果每次操作都给此段代码加锁,太浪费时间了而且也很浪费资源,降低程序的效率,因为读操作不会修改数据,只是做一些查询,所以在读的时候不用给此段代码加锁,可以共享的访问,只有涉及到写的时候,互斥的访问就好了

    三、读写锁的行为

    读写之间是互斥的—–>读的时候写阻塞,写的时候读阻塞,而且读和写在竞争锁的时候,写会优先得到锁

    这里写图片描述

    四、自旋锁&挂起等待是锁?

    1.自旋锁

    自旋锁是在发生获取不到锁的时候,会直接等待,不会被CPU直接调度走,而是会一直等到获取到锁,因为此锁是一直的在等待,所以不会有调度的开销,故此锁的效率比挂起等待锁的效率高,但是此锁会因不停的查看锁的释放情况,故会浪费更多的CPU资源

    2.挂起等待锁

    挂起等待锁是当某线程在执行临界区的代码时,那其他线程只能挂起等待,此时这些线程会被CPU调度走,等到锁释放(即就是临界区的代码被之前的那个线程已经执行完毕),而且被CPU调度的线程只有被调度回来才可以执行临界区的代码
    挂起等待锁是在发生获取不到锁的时候,他会被CPU调度走,去做别的事,但是会时不时的去查看锁有没有被释放
    ps:线程想执行临界区的代码的条件:
    (1)锁释放;
    (2)被CPU调度回来

    3.自旋锁的优缺点

    优点:效率高,避免了线程之间调度的开销
    缺点:浪费CPU资源
    

    4.挂起等待锁的优缺点

    优点:不会浪费CPU的资源,比较灵活
    缺点:效率不高,很可能会使临界区的代码不被任何线程执行,因为可能会是线程被
         CPU调度走了但是却没有被调度回来

    五、读写锁是怎么实现?

    1.一种交易场所(存放数据的地方):可以是变量、链表、数组或其他数据结构
    2.两种角色:读操作和写操作
    3.三种关系:(1)读和读之间没有关系
                   (2) 写和写之间是互斥关系
                   (3)读和写之间是同步互斥关系
    ps:同步---->读和写在同时竞争锁的时候,写会优先的得到锁
        互斥---->读的时候写阻塞,写的时候读阻塞
    

    4.相关函数

    (1)pthread_rwlock_init()—->初始化函数

    功能:初始化读写锁
    头文件:#include<pthread.h>
    int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthred_rwlockattr_t *restrict attr);
    参数说明:
    rwlock:是要进行初始化的
    attr:是rwlock的属性
    ps:此参数一般不关注,可设为NULL

    (2)pthread_rwlock_destroy—->销毁函数

    功能:销毁初始化的锁
    头文件:#include<pthread.h>
    int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
    参数说明:
    rwlock:是需要进行销毁的锁
    

    (3)加锁和解锁

    在进行读操作的时候加的锁:
    pthread_rwlock_rdlock(pthread_rwlock_t* rwlock);
    在进行写操作的时候加的锁:
    pthread_rwlock_wrlock(pthread_rwlock_t* rwlock);
    对读/写统一进行解锁:
    pthread_rwlock_unlock(pthread_rwlock_t* rwlock);
    

    六、代码实现读写锁

    #include<stdio.h>
    #include<unistd.h>
    #include<malloc.h>
    #include<stdlib.h>
    #include<pthread.h>
    pthread_rwlock_t rwlock;//声明读写锁
    int count;
    //写者线程的入口函数
    void*route_write(void*arg)
    {
        int i=*(int*)arg;//i是写者线程的编号
        free(arg);
        while(1){
            int t=count;
            //加锁
            pthread_rwlock_wrlock(&rwlock);
            printf("route_write:%d,%#x,count=%d,++count=%d\n",i,\
                    pthread_self(),t,++count);
            //解锁
            pthread_rwlock_unlock(&rwlock);
            sleep(1);
        }
    }
    //读者线程的入口函数
    void*route_read(void*arg)
    {
        int i=*(int*)arg;//i是读者线程的编号
        free(arg);
        while(1){
            //加锁
            pthread_rwlock_rdlock(&rwlock);
            printf("route_read:%d,%#x,count=%d\n",i,pthread_self(),count);
            //解锁
            pthread_rwlock_unlock(&rwlock);
            sleep(1);
        }
    }
    int main()
    {
        int i=0;
        //初始化读写锁
        pthread_rwlock_init(&rwlock,NULL);
        pthread_t tid[8];
        //创建3个写者线程
        for(i=0;i<3;i++){
            int*p=(int*)malloc(sizeof(int));
            *p=i;
            pthread_create(&tid[i],NULL,route_write,(void*)p);
        }
        //创建3个读者线程
        for(i=0;i<5;i++){
            int*p=(int*)malloc(sizeof(int));
            *p=i;
            pthread_create(&tid[i+3],NULL,route_read,(void*)p);
        }
        //主线程等待新创建的线程
        for(i=0;i<8;i++)
            pthread_join(tid[i],NULL);
        //销毁读写锁
        pthread_rwlock_destroy(&rwlock);
        return 0;
    }

    运行结果:
    这里写图片描述

    展开全文
  • 关于linux读写锁

    2016-04-07 20:09:02
     下面这个程序就是读写锁的程序,分别有两个读者,两个写着,当写着输入end的时候并且读者读到程序运行结束,里面的读写锁是动态初始化,最后用pthread_join(),主要主线程等待子线程运行完她才可以结束。...

            这次当我给面试官提及到读写锁的时候,详细问了我的读写锁,我知道怎么回事,用法,但是具体没实践过,听过的还是不要给面试官说了,不然又给自己挖坑。

       下面这个程序就是读写锁的程序,分别有两个读者,两个写着,当写着输入end的时候并且读者读到程序运行结束,里面的读写锁是动态初始化,最后用pthread_join(),主要主线程等待子线程运行完她才可以结束。对于现在锁,我才感觉到都是有套路的,都被玩坏了。初始化,处理的,最后是销毁的。此外,我还遇到的一个问题是当时忘记在写线程忘记休眠sleep,结果一直让我写,写,写,那么她就一直拿着cpu写,就算输入end也就结束不了,因为读线程根本执行不到。


    #include <stdio.h>
    #include <unistd.h>
    #include <string.h>
    #include <stdlib.h>
    #include <pthread.h>
    #include <bits/pthreadtypes.h>
    
    
    #define  WORK_SIZE  1024
    
    static  pthread_rwlock_t  rwlock;
    
    char work_area[WORK_SIZE];
    int time_to_exit;
    
    void *thread_to_read_o(void *arg);
    void *thread_to_read_t(void *arg);
    void *thread_to_write_o(void *arg);
    void *thread_to_write_t(void *arg);
    
    
    void *thread_to_read_o(void *arg)
    {
        printf("thread read one try to get lock\n");
    
        pthread_rwlock_rdlock(&rwlock);
        while(strncmp("end",work_area,3) != 0){
            printf("this is thread read one\n");
            printf("the characters is %s\n",work_area);
            pthread_rwlock_unlock(&rwlock);
            sleep(2);
            pthread_rwlock_rdlock(&rwlock);
            while(work_area[0] == '\0'){
               pthread_rwlock_unlock(&rwlock);
               sleep(2);
               pthread_rwlock_rdlock(&rwlock);
            }
        }
        pthread_rwlock_unlock(&rwlock);
        time_to_exit = 1;
        pthread_exit(0);
    }
    
    void *thread_to_read_t(void *arg)
    {
        printf("thread read one try to get lock\n");
    
        pthread_rwlock_rdlock(&rwlock);
        while(strncmp("end",work_area,3) != 0){
            printf("this is thread read two\n");
            printf("the characters is %s\n",work_area);
            pthread_rwlock_unlock(&rwlock);
            sleep(5);
            pthread_rwlock_rdlock(&rwlock);
            while(work_area[0] == '\0'){
                 pthread_rwlock_unlock(&rwlock);
                 sleep(5);
                 pthread_rwlock_rdlock(&rwlock);
            }
        }
        pthread_rwlock_unlock(&rwlock);
        time_to_exit = 1;
        pthread_exit(0);
    }
    void *thread_to_write_o(void *arg)
    {
        printf("this is write thread one try to get lock\n");
        while(!time_to_exit){
               pthread_rwlock_wrlock(&rwlock);
               printf("this is write thread one\n,input some text,enter 'end'  to finish\n");
               fgets(work_area,WORK_SIZE,stdin);
               pthread_rwlock_unlock(&rwlock);
               sleep(15); // forget sleep,so write always
        }
    
        pthread_rwlock_unlock(&rwlock);
        pthread_exit(0);
    }
    void *thread_to_write_t(void *arg)
    {
        sleep(10);
        while(!time_to_exit){
           pthread_rwlock_wrlock(&rwlock);
           printf("this is write thread two\n input some text,enter 'end' to finish\n");
           fgets(work_area,WORK_SIZE,stdin);
           pthread_rwlock_unlock(&rwlock);
           sleep(20);
        }
        pthread_rwlock_unlock(&rwlock);
        pthread_exit(0);
    }
    
    
    
    
    int main(int argc,char *argv[])
    {
        int retval;
        pthread_t a_thread,b_thread,c_thread,d_thread;
        void *thread_result;
    
        retval = pthread_rwlock_init(&rwlock,NULL);
        if(retval != 0){
              //  error
              exit(1);
        }
    
        retval = pthread_create(&a_thread,NULL,thread_to_read_o,NULL);
        if(retval != 0){
              //  error
              exit(1);
        }
    
        retval = pthread_create(&b_thread,NULL,thread_to_read_t,NULL);
        if(retval != 0){
              //  error
              exit(1);
        }
    
        retval = pthread_create(&c_thread,NULL,thread_to_write_o,NULL);
        if(retval != 0){
              //  error
              exit(1);
        }
        retval = pthread_create(&d_thread,NULL,thread_to_write_t,NULL);
        if(retval != 0){
              //  error
              exit(1);
        }
    
        // suspend main thread
        pthread_join(a_thread,NULL);
    
        pthread_join(b_thread,NULL);
    
        pthread_join(c_thread,NULL);
    
        pthread_join(d_thread,NULL);
    
    
        // destroy rwlock
        pthread_rwlock_destroy(&rwlock);
    
        printf("main thread will exit\n");
    
        return 0;
    }
    

      


    关于读写锁的第二个程序,主要是测试读锁和写锁哪个更加优先的问题,linux默认的是读者优先

    #include <stdio.h>
    #include <pthread.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    pthread_rwlock_t rwlock;
    
    void *readers(void *arg)
    {
        pthread_rwlock_rdlock(&rwlock);
        printf("readers %d got the lock\n",(int)arg);
        pthread_rwlock_unlock(&rwlock);
    }
    
    void *writes(void *arg)
    {
        pthread_rwlock_wrlock(&rwlock);
        printf("write %d got the lock\n",(int)arg);
        pthread_rwlock_unlock(&rwlock);
    }
    
    int main(int argc,char *argv[])
    {
        int retval,i;
        pthread_t writer_id,reader_id;
        pthread_attr_t attr;
        int nreadercount = 1;
        int nwritercount = 1;
    
        if(argc != 2){
             // error
             exit(1);
        }
    
        retval = pthread_rwlock_init(&rwlock,NULL);
        if(retval != 0){
            //error
            exit(2);
        }
    
        pthread_attr_init(&attr);
        pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
    
    
     //   pthread_rwlock_wrlock(&rwlock);
        pthread_rwlock_rdlock(&rwlock);
        for(i = 0; i < atoi(argv[1]);i++){
           if(random() % 2){
                pthread_create(&reader_id,&attr,readers,(void *)nreadercount);
                printf("create reader %d\n",nreadercount++);
           }else{
                pthread_create(&writer_id,&attr,writes,(void *)nwritercount);
                printf("create writer %d\n",nwritercount++);
           }
        }
    
      //  sleep(10);
        pthread_rwlock_unlock(&rwlock);
        sleep(10);
        return 0;
    }
    

    在上面的程序中如果有这个pthread_rwlock_wrlock(&rwlock);那么就算读者先加锁了,这时写者来了,那么再来的读者就不能加锁了,写者一直等到第一个读者结束后自己在加锁。理论是这样的,但是实际的结果,确实有点偏差,先看图


    第6个读者先得到了锁,我感觉这个里面做了优化,前9个因为加锁的缘故只能先创建完之后再执行线程,最后一个readers 6,内核已经知道迟早readers 6要执行的,既然内核现在拿着这个reader 6,内核就顺便执行,才不管你有么有pthread_rwlock_wrlock(&rwlock)


    在上面的程序中如果有这个pthread_rwlock_rdlock(&rwlock),运行结果



    如果有什么问题,欢迎指正

    展开全文
  •  1)读写锁的三种状态:读,写加锁  2)读写锁特性(12字):写优先级高,写独占,读共享  1&gt;写模式加锁时,解锁前,所有对该线程加锁的线程都会被阻塞。  2&gt;读模式加锁时,如果线程...

    (1)读写锁:只有一把锁,但是有两种状态(读,写)

                 1)读写锁的三种状态:读锁,写锁,不加锁

                 2)读写锁特性(12字):写锁优先级高,写独占,读共享

                        1>写模式加锁时,解锁前,所有对该线程加锁的线程都会被阻塞。

                        2>读模式加锁时,如果线程是读加锁则成功,如果线程是写加锁会阻塞。

                       3>读锁、写锁并行阻塞时,写锁优先级高,即解锁后优先执行写锁操作。

               3)读写锁非常适合对数据读的次数比写的次数多。

    (2)读写锁函数:成功返回0,失败直接返回错误号。

                      pthread_rwlock_t类型 用于定义一个读写锁变量

              1)pthread_rwlock_init:初始化一把读写锁

                    int pthread_rwolck_init(pthread_rwlock_t*restrict rwlock,const pthread_rwlockattr_t*restrict attr);    

                   restrict关键字:只用于限制指针,所有修改该指针指向内存中内容的操作,只能通过本指针来完成,不能通过除本指针之外的其它变量或指针修改。

                  参数2:attr表读写属性,通常使用NULL,表示默认属性

             2)销毁一把读写锁:pthread_rwlock_destroy

                   int pthread_rwlock_destroy(pthread_rwlock_t * rwlock);   

            3)以读方式请求加锁:pthread_rwlock_rdlock

                    int pthread_rwlock_rdlock(pthread_rwlock_t * rwlock);   

            4)以写方式请求加锁:pthread_rwlock_rdlock

                    int pthread_rwlock_wrlock(pthread_rwlock_t * rwlock);    

            5)解锁:pthread_rwlock_unlock

                   int pthread_rwlock_unlock(pthread_rwlock_t * rwlock);   

            6)非阻塞请求读锁:pthread_rwlock_tryrdlock

                    int pthread_rwlock_tryrdlock(pthread_rwlock_t * rwlock); 

            7)非阻塞请求写锁:pthread_rwlock_trywrlock

                    int pthread_rwlock_trywrock(pthread_rwlock_t * rwlock); 

    (3)读写锁示例:多个线程对同一全局数据进行读写操作

                      

               

    展开全文
  • linux多线程之读写锁

    2018-07-14 18:13:41
    基本概念: 读写锁也叫做共享互斥。 当读写锁是写加锁状态时...与互斥量相比,读写锁在使用之前必须初始化,在释放它们底层的内存之前必须销毁。 一、初始化与销毁 PTHREAD_RWLOCK_DESTROY(P) POSIX Programmer


    基本概念:

    读写锁也叫做共享互斥锁。

    当读写锁是写加锁状态时,在这个锁被解锁之前,所有试图对这个锁加锁的线程都会被阻塞。当读写锁在读加锁状态,所有试图以读模式对它进行加锁的线程都可以得到访问权。

    与互斥量相比,读写锁在使用之前必须初始化,在释放它们底层的内存之前必须销毁。


    一、锁的初始化与销毁

    PTHREAD_RWLOCK_DESTROY(P)  POSIX Programmer's Manual PTHREAD_RWLOCK_DESTROY(P)
    
    NAME
           pthread_rwlock_destroy,  pthread_rwlock_init - destroy and initialize a
           read-write lock object
    
    SYNOPSIS
           #include <pthread.h>
    
           int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
           int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,
                  const pthread_rwlockattr_t *restrict attr);
    
    两个函数的返回值:若成功,返回0;否则,返回错误编号


    二、读锁

    PTHREAD_RWLOCK_RDLOCK(P)   POSIX Programmer's Manual  PTHREAD_RWLOCK_RDLOCK(P)
    
    NAME
           pthread_rwlock_rdlock,  pthread_rwlock_tryrdlock  -  lock  a read-write
           lock object for reading
    
    SYNOPSIS
           #include <pthread.h>
    
           int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
           int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
    两个函数的返回值:若成功,返回0;否则,返回错误编号
    pthread_rwlock_tryrdlock函数可以获取锁时,返回0.否则,返回错误EBUSY


    三、写锁

    PTHREAD_RWLOCK_TRYWRLOCK(P)POSIX Programmer's ManuaPTHREAD_RWLOCK_TRYWRLOCK(P)
    
    NAME
           pthread_rwlock_trywrlock,  pthread_rwlock_wrlock  -  lock  a read-write
           lock object for writing
    
    SYNOPSIS
           #include <pthread.h>
    
           int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
           int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
    两个函数的返回值:若成功,返回0;否则,返回错误编号

    pthread_rwlock_trywrlock函数可以获取锁时,返回0.否则,返回错误EBUSY


    四、带有超时的读写锁

    PTHREAD_RWLOCK_TIMEDWRLOCK(POSIX Programmer's ManPTHREAD_RWLOCK_TIMEDWRLOCK(P)
    
    NAME
           pthread_rwlock_timedrdlock - lock a read-write lock for reading
           pthread_rwlock_timedwrlock - lock a read-write lock for writing
    
    SYNOPSIS
           #include <pthread.h>
           #include <time.h>
    
           int pthread_rwlock_timedrdlock(pthread_rwlock_t *restrict rwlock,
                  const struct timespec *restrict abs_timeout);
           int pthread_rwlock_timedwrlock(pthread_rwlock_t *restrict rwlock,
                  const struct timespec *restrict abs_timeout);
    两个函数的返回值:若成功,返回0;否则,返回错误编号
    如果它们不能获取锁,那么超时到期时,这两个函数将返回ETIMEDOUT


    五、解锁

    PTHREAD_RWLOCK_UNLOCK(P)   POSIX Programmer's Manual  PTHREAD_RWLOCK_UNLOCK(P)
    
    NAME
           pthread_rwlock_unlock - unlock a read-write lock object
    
    SYNOPSIS
           #include <pthread.h>
    
           int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
    返回值:若成功,返回0;否则,返回错误编号

    读写锁属性:

    读写锁支持的唯一属性是进程共享属性。它与互斥量的进程共享属性是相同的,这里不展开讨论。


    例子:gcc pthread_rwlock.c -pthread

    #include <pthread.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <errno.h>
    
    static int num = 0;
    static int count = 100000;
    static pthread_rwlock_t rwlock;
    
    void Perror(const char *s)
    {
        perror(s);
        exit(EXIT_FAILURE);
    }
    
    void* fun2(void *arg)
    {
        pthread_t thread_id = pthread_self();
        printf("the thread2 id is %ld\n", (long)thread_id);
        int i = 1;
        for (; i<=count; ++i) {
            pthread_rwlock_wrlock(&rwlock);
            num += 1;
            pthread_rwlock_unlock(&rwlock);
        }
    }
    
    void* fun3(void *arg)
    {
        pthread_t thread_id = pthread_self();
        printf("the thread3 id is %ld\n", (long)thread_id);
        int i = 1;
        for (; i<=count; ++i) {
            pthread_rwlock_wrlock(&rwlock);
            num += 1;
            pthread_rwlock_unlock(&rwlock);
        }
    }
    
    int main()
    {
        int err;
        pthread_t thread1;
        pthread_t thread2;
        pthread_t thread3;
    
        // init
        pthread_rwlock_init(&rwlock, NULL);
    
        thread1 = pthread_self();
        printf("the thread1 id is %ld\n", (long)thread1);
    
        // Create thread
        err = pthread_create(&thread2, NULL, fun2, NULL);
        if (err != 0) {
            Perror("can't create thread2\n");
        }
        err = pthread_create(&thread3, NULL, fun3, NULL);
        if (err != 0) {
            Perror("can't create thread3\n");
        }
    
        // detach thread
        err = pthread_detach(thread2);
        if (err != 0) {
            Perror("can't detach thread2\n");
        }
        err = pthread_detach(thread3);
        if (err != 0) {
            Perror("can't detach thread3\n");
        }
    
        int i = 1;
        for (; i<=count; ++i) {
            pthread_rwlock_rdlock(&rwlock);
            int temp = num;
            pthread_rwlock_unlock(&rwlock);
        }
    
        sleep(10);
        printf("The num is %d\n", num);
        
        pthread_rwlock_destroy(&rwlock);
        return 0;
    }
    


    参考:《unix环境高级编程》·第三版

    End;

    展开全文
  • Linux读写锁介绍

    2014-05-14 14:32:04
    读写锁 (rwlock)功能特点简介 读写锁实际是一种特殊的自旋,它把对共享资源的访问者划分成读者和写者,读者只对...写者是排他性的,一个读写锁同时只能有一个写者或多个读者(与CPU数相关),但能同时既有读者又有
  • Linux多线程之读写锁

    2018-03-28 15:35:40
    概述一般大家对读写锁应该有一个认知,当读数据比修改数据频繁,我们可以采用读写锁读写锁的分配规则如下:只要没有线程持有某个给定的读写锁用于写时,那么任意数目的线程可以持有该读写锁用于读;仅当没有线程...
  • Linux 读写锁

    2018-09-04 09:49:03
    1.读写锁是几把 一把 pthread_rwlock_t lock; 2.读写锁的类型 读 - 对内存做读操作 写 - 对内存做写操作 3.读写锁的特性 线程A加读成功,又来了三个线程,做读操作,可以加锁成功 线程A加写...
  • linux 读写锁应用实例

    2014-03-26 00:04:05
    /*使用读写锁实现四个线程读写一段程序的实例,共创建了四个新的线程,其中两个线程用来读取数据,另外两个线程用来写入数据。在任意时刻,如果有一个线程在写数据,将阻塞所有其他线程的任何操作。*/ #include #...
  • linux读写锁的理解

    2011-10-27 23:43:26
    读写锁实际是一种特殊的自旋,它把对共享资源的访问者划分成读者和写者,读者只对共享资源进行读访问,写者则需要对共享资源进行写操作。这种相对于自旋而言,能提高并发性,因为在多处理器系统中,它允许同时...
  • 读写锁函数2.1 读写锁初始化2.2 读写锁销毁2.3 申请读2.4 申请写2.5 释放读写锁03. 读写锁应用示例04. 附录 01. 读写锁概述 当有一个线程已经持有互斥时,互斥将所有试图进入临界区的线程都阻塞住。但是...
  • 读写锁和互斥量(互斥)很类似,是另一种线程同步机制,但属于POSIX标准,可以用来同步同一进程中的各个线程。当然如果一个读写锁存放在多个进程共享的某个内存区中,那么还可以用来进行进程间的同步, 读写锁的...
  • Linux中常见的主要有: 互斥读写锁、自旋。这三种的使用以及区别将在下面一步步深入了解。 1 互斥 1.1 互斥的作用 互斥(也称互斥量)可以用于保护关键代码段,以确保其独占式的访问,和有点像一...
  • 读写锁比mutex有更高的适用性,可以多个线程同时占用读模式的读写锁,但是只能一个线程占用写模式的读写锁。 1. 当读写锁是写加锁状态时,在这个被解锁之前,所有试图对这个加锁的线程都会被阻塞; 2. 当读写...
  • http://sourceware.org/ml/glibc-bugs/2008-11/msg00073.htmlhttp://www.nabble.com/-Bug-nptl-7057--New:-pthread-rwlock-does-not-implement-writer-preferred-option-td20703744.html pthread rwlock doe
  • 互斥试图将想进入临界区的所有线程都阻塞住,但是有时候该临界区会涉及由这些线程共享的一个或多个数据的访问或更新,这时候我们就需要用到读写锁。系统读写锁的分配规则: (1)只要有没有线程持有给定的读写锁...
  • Linux 读写自旋原理

    2012-02-08 15:30:35
    简介: 读写自旋是一种特殊的自旋,它将访问共享资源的线程区分为读者和写者,多个读者可以同时持有,因而提高 了线程的并发性。本系列由三篇文章组成,本文是系列文章的第一部分,以自动机的观点阐述读写...
  • 基本概念: 并发:多个执行单元同时发生 “执行单元”:硬件中断、软中断、进程 竞态:多个执行单元同时访问共享资源产生竞态 产生竞态的条件: 1,必须有多个执行单元 2,必须有共享资源 3,必须同时访问 ...
  • 读写锁是另一种实现线程间同步的方式。与互斥量类似,但读写锁将操作分为读、写两种方式,可以多个线程同时占用读模式的读写锁,这样使得读写锁具有更高的并行性。...虽然读写锁有读、写加锁三种状态...
  • 读写锁 什么是读写锁读写锁是从互斥中发展下来的,读写锁将访问中的读操作和写操作区分开来对待,把对资源的共享者划分成读者和写者,读者只对共享资源进行读访问,写者则需要对共享资源进行写操作。在某些...
1 2 3 4 5 ... 20
收藏数 93,516
精华内容 37,406