Heim  >  Artikel  >  System-Tutorial  >  Wie wähle ich Mutex-Sperren, Lese-/Schreibsperren, Spin-Sperren und Semaphoren im Linux-Kernel aus?

Wie wähle ich Mutex-Sperren, Lese-/Schreibsperren, Spin-Sperren und Semaphoren im Linux-Kernel aus?

WBOY
WBOYnach vorne
2024-02-11 18:30:12782Durchsuche

1. Vorwort

Es gibt viele verschiedene Arten von Sperren im Linux-Kernel, und sie alle können zum Schutz kritischer Ressourcen verwendet werden, um Race-Bedingungen zwischen mehreren Threads oder Prozessen zu vermeiden und so die Stabilität und Zuverlässigkeit des Systems zu schützen. Zu den Arten dieser Sperren gehören: Mutex-Sperren (mutex)、读写锁(rwlock)、自旋锁(spinlock)和信号量(semaphore). Heute werde ich Ihnen die verschiedenen Sperren im Linux-Kernel vorstellen und wie wir auswählen, welche Sperre wir in realen Projekten verwenden.

Wie wähle ich Mutex-Sperren, Lese-/Schreibsperren, Spin-Sperren und Semaphoren im Linux-Kernel aus?

2. Einführung in verschiedene Arten von Schlössern

Mutex-Sperren (mutex 是一种常用的锁,它可以保护共享资源,使得在某个时刻只有一个线程或进程能够访问它。读写锁(rwlock)则可以同时允许多个线程或进程读取共享资源,但只允许一个线程或进程写入它。自旋锁(spinlock)可以用来保护共享资源,使得在某个时刻只有一个线程或进程能够访问它,但它会使线程或进程“自旋”,直到获得锁为止。最后,信号量(semaphore) können verwendet werden, um den Zugriff auf gemeinsam genutzte Ressourcen zu steuern, um sicherzustellen, dass andere Threads oder Prozesse sicher darauf zugreifen können.

Lese-/Schreibsperre (rwlock) ist ein Synchronisierungsmechanismus, der zur Steuerung des Multithread-Zugriffs auf gemeinsam genutzte Ressourcen verwendet wird. Wenn ein Thread eine gemeinsam genutzte Ressource lesen muss, kann er eine Lesesperre erwerben, sodass andere Threads die Ressource gleichzeitig ohne Konflikte lesen können. Wenn ein Thread auf eine gemeinsam genutzte Ressource schreiben muss, kann er eine Schreibsperre erwerben, sodass andere Threads nicht auf die Ressource zugreifen können, wodurch Datenintegrität und -konsistenz sichergestellt werden.

Spin lock (Spinlock)spinlock 是一种简单而有效的用于解决多线程同步问题的锁。它是一种排他锁,可以在多线程环境下保护共享资源,以防止多个线程同时访问该资源。自旋锁的基本原理是,在一个线程试图获取锁时,它会不断尝试获取锁,直到成功为止。在这期间,线程不会进入休眠状态,而是一直处于忙等待(busy-waiting ist eine einfache und effektive Sperre, die zur Lösung von Multithread-Synchronisierungsproblemen verwendet wird. Es handelt sich um eine exklusive Sperre, die gemeinsam genutzte Ressourcen in einer Multithread-Umgebung schützt und verhindert, dass mehrere Threads gleichzeitig auf die Ressource zugreifen. Das Grundprinzip einer Spin-Sperre besteht darin, dass ein Thread, wenn er versucht, eine Sperre zu erhalten, so lange versucht, die Sperre zu erlangen, bis ihm dies gelingt. Während dieser Zeit wechselt der Thread nicht in den Ruhezustand, sondern ist immer damit beschäftigt, zu warten (busy-waiting) Zustand, von dem der Name des Spin-Locks stammt.

Semaphor (semaphore 是一种常用的同步机制,它可以用来控制多个线程对共享资源的访问。它有助于确保同一时间只有一个线程能够访问共享资源,从而避免资源冲突和竞争。信号量是一种整数计数器,用于跟踪可用资源的数量。当一个线程需要访问共享资源时,它首先必须获取信号量,这会将信号量的计数器减少 1), und wenn der Zugriff auf die gemeinsam genutzte Ressource abgeschlossen ist, muss er das Semaphor freigeben, damit auch andere Threads auf die gemeinsam genutzte Ressource zugreifen können.

4. Mutex

Mutex-Sperre ist der einfachste Sperrtyp und wird im Kernel häufig verwendet. Es handelt sich um eine binäre Sperre, die jeweils nur von einem Thread gehalten werden kann. Wenn ein Thread die Sperre anfordert und die Sperre bereits belegt ist, wird der Thread blockiert, bis die Sperre aufgehoben wird. Die Implementierung von Mutex-Sperren verwendet atomare Operationen, sodass die Leistung relativ hoch ist, aber auch anfällig für Deadlock-Situationen ist.

Im Kernel ist die Mutex-Sperre wie folgt definiert:

struct mutex {
    raw_spinlock_t      wait_lock;
    struct list_head    wait_list;
    struct task_struct  *owner;
    int                 recursion;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
    struct lockdep_map  dep_map;
#endif
};

Die Verwendung von Mutex-Sperren ist sehr einfach und erfordert normalerweise nur den Aufruf von zwei Funktionen:

void mutex_init(struct mutex *lock):函数用于初始化互斥锁
void mutex_lock(struct mutex *lock):函数用于获取互斥锁
void mutex_unlock(struct mutex *lock):函数用于释放互斥锁

5. Lese-/Schreibsperre

Die Lese-/Schreibsperre ist eine spezielle Art von Sperre, die es mehreren Threads ermöglicht, gemeinsam genutzte Ressourcen gleichzeitig zu lesen, aber nur einem Thread das Schreiben auf gemeinsam genutzte Ressourcen ermöglicht. Die Implementierung der Lese-/Schreibsperre verwendet zwei Zähler, um die Anzahl der Lese-Threads und die Anzahl der Schreib-Threads aufzuzeichnen, die derzeit die Sperre halten.

Im Kernel ist die Lese-/Schreibsperre wie folgt definiert:

struct rw_semaphore {
    long            count;
    struct list_head    wait_list;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
    struct lockdep_map  dep_map;
#endif
};

Die Verwendung von Lese-/Schreibsperren ist ebenfalls relativ einfach. Zum Abschluss müssen normalerweise nur drei Funktionen aufgerufen werden:

init_rwsem(struct rw_semaphore *sem):函数用于初始化读写锁
down_read(struct rw_semaphore *sem):函数用于获取读锁
up_read(struct rw_semaphore *sem):函数用于释放读锁
down_write(struct rw_semaphore *sem):函数用于获取写锁
up_write(struct rw_semaphore *sem):函数用于释放写锁

6. Spinlock

Eine Spin-Sperre ist eine Sperre, die gemeinsam genutzte Ressourcen schützt. Sie belegt die CPU während des Wartens. Spin-Locks eignen sich für Situationen, in denen der kritische Abschnitt des Codes relativ klein ist und die exklusive Zeit der gemeinsam genutzten Ressource relativ kurz ist, sodass der Overhead des Kontextwechsels vermieden werden kann. Spin-Locks können nicht in kritischen Codeabschnitten verwendet werden, die Ruhezustand erfordern, da der Spin-Lock im Ruhezustand immer die CPU belegt.

Im Linux-Kernel verwenden Spinlocks spinlock_t类型表示,可以通过spin_lock()spin_unlock() Funktionen, um sie zu bearbeiten.

spin_lock_init(spinlock_t *lock):用于初始化自旋锁,将自旋锁的初始状态设置为未加锁状态。
spin_lock(spinlock_t *lock):用于获得自旋锁,如果自旋锁已经被占用,则当前进程会自旋等待,直到自旋锁可用。
spin_trylock(spinlock_t *lock):用于尝试获取自旋锁,如果自旋锁当前被占用,则返回0,否则返回1。
spin_unlock(spinlock_t *lock):用于释放自旋锁。

Bei der Verwendung von Spin-Locks müssen Sie auf folgende Punkte achten:

  • 自旋锁只适用于临界区代码比较短的情况,因为自旋等待的过程会占用CPU资源。
  • 自旋锁不可重入,也就是说,如果一个进程已经持有了自旋锁,那么它不能再次获取该自旋锁。
  • 在持有自旋锁的情况下,应该尽量避免调用可能会导致调度的内核函数,比如睡眠函数,因为这可能会导致死锁的发生。
  • 在使用自旋锁的时候,应该尽量避免嵌套使用不同类型的锁,比如自旋锁和读写锁,因为这可能会导致死锁的发生。
  • 当临界区代码较长或者需要睡眠时,应该使用信号量或者读写锁来代替自旋锁。

七、信号量(semaphore)

信号量是一种更高级的锁机制,它可以控制对共享资源的访问次数。信号量可分为二元信号量和计数信号量。二元信号量只有01两种状态,常用于互斥锁的实现;计数信号量则可以允许多个进程同时访问同一共享资源,只要它们申请信号量的数量不超过该资源所允许的最大数量。

在Linux内核中,信号量使用struct semaphore结构表示,可以通过down()up()函数对其进行操作。

void sema_init(struct semaphore *sem, int val):初始化一个信号量,val参数表示初始值。
void down(struct semaphore *sem):尝试获取信号量,如果信号量值为 0,调用进程将被阻塞。
int down_interruptible(struct semaphore *sem):尝试获取信号量,如果信号量值为 0,调用进程将被阻塞,并可以被中断。
int down_trylock(struct semaphore *sem):尝试获取信号量,如果信号量值为 0,则立即返回,否则返回错误。
void up(struct semaphore *sem):释放信号量,将信号量的值加 1,并唤醒可能正在等待信号量的进程。

八、该如何选择正确的锁

当需要对共享资源进行访问和修改时,我们通常需要采用同步机制来保证数据的一致性和正确性,其中锁是最基本的同步机制之一。不同类型的锁适用于不同的场景。

互斥锁适用于需要保护共享资源,只允许一个线程或进程访问共享资源的场景。例如,当一个线程正在修改一个数据结构时,其他线程必须等待该线程释放锁后才能修改该数据结构。

读写锁适用于共享资源的读写操作频繁且读操作远大于写操作的场景。读写锁允许多个线程同时读取共享资源,但只允许一个线程写入共享资源。例如,在一个数据库管理系统中,读取操作比写入操作频繁,使用读写锁可以提高系统的并发性能。

自旋锁适用于保护共享资源的访问时间很短的场景,当线程需要等待的时间很短时,自旋锁比互斥锁的性能更好。例如,在访问共享资源时需要进行一些简单的操作,如对共享资源进行递增或递减等操作。

信号量适用于需要协调多个线程或进程对共享资源的访问的场景,允许多个线程或进程同时访问共享资源,但同时访问的线程或进程数量有限。例如,在一个并发下载系统中,可以使用信号量来限制同时下载的文件数量。

举个生活中的例子:当我们在买咖啡的时候,柜台前可能会有一个小桶,上面写着“请取走您需要的糖果,每人一颗”这样的字样。这个小桶就是一个信号量,它限制了每个人能够取走的糖果的数量,从而保证了公平性。

如果我们把这个小桶换成互斥锁,那么就可以只允许一个人在柜台前取走糖果。如果使用读写锁,那么在非高峰期的时候,多个人可以同时取走糖果,但在高峰期时只允许一个人取走。

Und wenn wir dieses Fass durch einen Drehverschluss ersetzen, müssen andere, wenn jemand die Süßigkeiten wegnimmt, dort warten, bis die Süßigkeiten weggenommen werden. Dies kann zu Zeitverschwendung führen, da sich möglicherweise jemand anderes um dringendere Angelegenheiten kümmern muss.

9. Zusammenfassung

Im Linux-Kernel gibt es vier gängige Sperren: Mutex-Sperren, Lese-/Schreibsperren, Spin-Sperren und Semaphoren. Diese Sperren eignen sich für verschiedene Szenarien. Entwickler müssen basierend auf der tatsächlichen Situation geeignete Sperren auswählen, um die Korrektheit und Leistung des gleichzeitigen Zugriffs sicherzustellen.

Das obige ist der detaillierte Inhalt vonWie wähle ich Mutex-Sperren, Lese-/Schreibsperren, Spin-Sperren und Semaphoren im Linux-Kernel aus?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:lxlinux.net. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen