[linux] spin lock and read-write lock

1. Spin lock

1.1 Suspend wait and spin wait

Let's look at two scenarios first:
1️⃣ When a thread applies for a lock and finds that it cannot apply, it goes to do other things. This state is called hanging and waiting . Waiting for the lock to be released before being woken up.
2️⃣ When a thread applies for a lock and finds that it cannot apply, it keeps asking whether the lock is released. We call this situation spin waiting .

But what determines the manner of waiting?

Depends on how long we have to wait . That is, how long a thread that has successfully applied for a critical resource must stay in the critical section.

So how to define the length of time?

We can look at the usage scenario. When there are many IO operations or waiting for certain software conditions... generally it is necessary to hang and wait. If the memory operation is very simple in the critical section, it is usually spin waiting.

In general, we will choose to suspend waiting , because if a deadlock occurs when using spin waiting, all execution flows will spin crazily, which will quickly occupy CPU resources.

And because it is up to the programmer to choose which waiting method to choose, we can also use both methods to test the effect to see who is good and who is bad.

1.2 Spinlock interface

The lock pthread_mutex and semaphore sem we introduced earlier belong to the category of pending waiting.

And the spinlock also has its own type:

pthread_spinlock_t *lock

1.2.1 Initialization and destruction of spin locks

#include <pthread.h>

int pthread_spin_destroy(pthread_spinlock_t *lock);
int pthread_spin_init(pthread_spinlock_t *lock, int pshared);

1.2.2 Locking and unlocking of spin locks

Lock:

#include <pthread.h>

int pthread_spin_lock(pthread_spinlock_t *lock);
int pthread_spin_trylock(pthread_spinlock_t *lock);

unlock:

#include <pthread.h>

int pthread_spin_unlock(pthread_spinlock_t *lock);

It can be seen that the interface of the mutex lock we used before is similar. In fact, it is practically the same as a mutex lock. In the eyes of users, whether it is hanging waiting or spinning waiting, it is waiting .

2. Reader-writer model

2.1 Scene introduction

When we were young, we all had the experience of drawing blackboard newspapers. We called the person who drew the blackboard newspaper the writer , and the person who read the blackboard newspaper was called the reader .
Let's discuss the relationship between them:
Writer vs Writer:

The relationship between writers and writers is a typical mutual exclusion relationship (regardless of the situation of drawing in different areas), because coverage may occur.

Readers and Writers:

When the writer has not finished writing, the reader may read it, so that the reader does not know what he has read, so there should be a mutually exclusive relationship between them.
There is also a situation where the writer has finished writing, and no one has read it and then erased it, and updated the blackboard, what is the point of that? So there must be a synchronous relationship between readers and writers .

Readers and Readers:

There is no relationship between readers and readers , there is no mutual exclusion or synchronization. Because everyone can read the blackboard newspaper.

The difference between this and the [linux] producer-consumer model (condition variable) based on blocking queues we talked about before is that the consumer will take the data, but the reader will not.

So what scenarios does the reader-writer problem apply to?

Once published, it will not be modified for a long time, and it is read most of the time, such as our blog.

2.2 Interface of read-write lock

2.2.1 Initialization and destruction of read-write lock

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

2.2.2 Locking and unlocking of read-write locks

Reader lock:

#include <pthread.h>

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

Writer lock:

#include <pthread.h>

int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

Reader and writer locking are different interfaces, but unlocking is one interface.
unlock:

#include <pthread.h>

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

2.3 Pseudo-code principle

The reader has a lock and a counter:

pthread_mutex_t rdlock;
int rdcnt = 0;

The writer also has its own lock:

pthread_mutex_t wrlock;

When the reader reads the data:

lock(&rdlock);
rdcnt++;
if(rdcnt == 1)
{
    
    
	// 不让写者进来
	lock(&wrlock);
}
unlock(&rdlock);

// 读取数据……
lock(&rdlock);

rdcnt--;
if(rdcnt == 0)
{
    
    
	// 现在可以让写者进入
	unlock(&wrlock);
}
unlock(&rdlock);

The writing process for writers is much simpler:

lock(&wrlock);
// 写入
unlock(&wrlock);

At any one time, only one writer is allowed to write, but multiple readers are allowed to read .

2.4 Reader Priority and Writer Priority

When there are multiple readers, it is very likely that the writer will not be able to enter, causing the writer’s hunger problem, and this is normal. After all, the reader-writer model is to be in the reading state most of the time, and we manage this state It's called reader priority .

So what about writers first?

For example, there are now ten readers, and five of them have already entered. At this time, the writer can stop the five that have not entered , and wait for the threads that entered to finish reading before writing.



Guess you like

Origin blog.csdn.net/qq_66314292/article/details/130373173