Talking about the use of read-write lock

1. What is a read-write lock?

The read-write lock is actually a kind of lock, which locks a section of critical section code, but this lock is mutually exclusive when writing, and can be shared to access the critical section when reading.
Read-write locks are similar to mutexes (mutexes). They are another thread synchronization mechanism, but they are not part of the POSIX standard and can be used to synchronize threads in the same process. Of course, if a read-write lock is stored in a memory area shared by multiple processes, it can also be used for synchronization between processes.

Rules for the use of read-write locks:

  1. As long as there is no lock in write mode, any thread can lock in read mode;
  2. Only when the read-write lock is in the unlocked state, can the lock in the write mode be performed;
  3. A read-write lock is also called a shared-exclusive lock. When a read-write lock is locked in read mode, it is locked in shared mode, and when it is locked in write mode, it is locked in exclusive mode. . The read-write lock is very suitable for applications where the frequency of reading data is much greater than the frequency of writing data. In this way, concurrent execution of multiple reader threads can be run at any time, which brings a higher degree of concurrency to the program.

ps: The read-write lock is essentially a spin lock

2. Why do I need a read-write lock?

Sometimes, in multithreading, there are fewer opportunities for modification of some public data, but there are many opportunities for reading. This public data is basically read. If you lock this code for each operation, It’s too time-consuming and also a waste of resources, which reduces the efficiency of the program. Because the read operation does not modify the data, but only performs some queries, so there is no need to lock this code when reading, and the shared access is only related to writing. Time, mutually exclusive access is just fine

Three, the behavior of the read-write lock

There is mutual exclusion between reading and writing —> When reading, writing is blocked, when writing is blocked, and when reading and writing are locked in contention, the write will get the lock first
Insert picture description here

Four, spin lock & suspend waiting lock (mutual exclusion lock)?

1. Spin lock

Spin locks will wait directly when the lock cannot be acquired, and will not be directly dispatched by the CPU, but will wait until the lock is acquired, because this lock is always waiting, so there will be no scheduling overhead Therefore, the efficiency of the lock is higher than the efficiency of the pending lock, but the lock will be constantly checking the release of the lock, so more CPU resources will be wasted

2. Suspend the waiting lock

Suspended waiting lock is when a thread is executing the code in the critical section, then other threads can only suspend and wait. At this time, these threads will be dispatched by the CPU and wait until the lock is released (that is, the code in the critical section is released by the previous thread It has been executed), and the thread scheduled by the CPU can only execute the code in the critical section when it is scheduled back.
Waiting for the lock is when the lock cannot be acquired, it will be dispatched by the CPU to do other things, but Will check whether the lock has been released from time to time.
ps: The condition for the thread to execute the code in the critical section:
(1) The lock is released;
(2) It is scheduled back by the CPU

3. The advantages and disadvantages of spin locks

Advantages: high efficiency, avoiding the overhead of scheduling between threads.
Disadvantages: waste of CPU resources

4. The advantages and disadvantages of suspending waiting locks

Advantages:
Does not waste CPU resources, and is more flexible. Disadvantages: Inefficient, it is possible that the code in the critical section will not be executed by any thread, because it may be that the thread is
dispatched by the CPU but is not dispatched back

The difference from a mutex is that the mutex will block all threads trying to enter the protected critical section; however, the read-write lock will judge whether it is allowed or not based on the attributes of the thread that currently enters the critical section and the thread requesting to enter the critical section. The thread enters.

The relative mutex has only two states: locked and unlocked. The read-write lock has three states: lock in read mode, lock in write mode, and no lock.

5. How is the read-write lock implemented?

1. A trading place (a place where data is stored): it can be a variable, a linked list, an array or other data structures
2. Two roles: read operation and write operation
3. Three relationships:
(1) There is no between read and read Relationship
(2) The relationship between writing and writing is mutually exclusive
(3) The relationship between reading and writing is synchronous and mutually exclusive

ps: Synchronization---->When reading and writing compete for lock at the same time, write will get the lock first.
Mutual exclusion---->write blocking when reading, and reading blocking when writing

Related functions
(1) pthread_rwlock_init() —->initialization function

Function: Initialize the read-write lock
Header file: #include<pthread.h>

int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthred_rwlockattr_t *restrict attr);

Parameter description:
rwlock: is the
attr to be initialized : is the attribute of rwlock
ps: this parameter is generally not concerned, can be set to NULL

(2) pthread_rwlock_destroy—-> destroy function

Function: Destroy the initialized lock
header file: #include<pthread.h>

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

Parameter description:
rwlock: is the lock that needs to be destroyed

(3) Lock and unlock

Locks added during read operations:

pthread_rwlock_rdlock(pthread_rwlock_t* rwlock);

Locks added during write operations:

pthread_rwlock_wrlock(pthread_rwlock_t* rwlock);

Unlock the read/write uniformly:

pthread_rwlock_unlock(pthread_rwlock_t* rwlock);

Six, the code realizes the read-write lock

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

Guess you like

Origin blog.csdn.net/xp178171640/article/details/106272020