This is a creation in Article, where the information may have evolved or changed.
Golang mutexes and read-write locks
The Golang Sync package implements two types of lock mutexes (mutexes) and Rwmutex (read and write locks), where Rwmutex is implemented based on mutexes, and read-only locks are implemented using similar functions as reference counters. Type Mutex func (M *mutex) Lock () func (M *mutex) Unlock () Type Rwmutex func (RW * Rwmutex) Lock () func (rw *rwmutex) Unlock () func (rw *rwmutex) Rlock () func (rw *rwmutex) RUn Lock () func (rw *rwmutex) Rlocker () Locker 1, Mutex lock func (M *mutex) lock (): Lock, Unlock () Unlock, use Lock ( After the lock is added, it cannot be locked again until it is unlocked with unlock () unlocked before it can be locked again. For read-write uncertainty scenarios where there is no obvious difference between read and write times and only one read or write is allowed, the lock is also called a global lock. Func (M *mutex) Unlock (): Unlocks, if not locked before using Unlock (), causes a run error. A locked mutex is not associated with a particular goroutine, so it can be locked with one goroutine and then unlocked with another goroutine. The mutex can only be locked once, and when it is unlocked again before unlocking it, it will deadlock (causing the current thread to block), and if unlocked before locking, it will error "Panic:sync:unlock of unlocked Mutex" 2, read-write lock Rwmutex is a read-write lock, the lock can To add more than one read lock or a write lock, it is often used to read far more than the number of writes. Func (rw *rwmutex) lock (): Write lock, if there are additional read and write locks before the write lock is added, lock blocks until the lock is available, and to ensure that the lock is finally available, the blocked lock call excludes the new read lock from the acquired lock, that is, the write lock permission is higher than the read lock. Write lock is preferred when there is a write lock. Func (rw *rwmutex) Unlock (): Write lock unlock, which causes a run-time error if no write lock is made. Func (rw *rwmutex) Rlock (): Read lock, when there is a write lock, cannot load read lock, when there is only read lock or no lock, can load read lock, read lock can load multiple, so it is suitable for "read more write less" scenario. Func (rw *rwmutex) Runlock (): Read lock unlock, Runlock revoke a single rlock call, it has no effect for other readers that exist simultaneously. If RW is not locked for reading, calling Runlock raises a run-time error. Read and write locks can only lock the write lock once, unlocked before the lock can be multiple times, read the lock may be many times, but read the maximum number of locks than the number of read the lock more than once, under normal circumstances we do not recommend reading the number of extra lock read lock times. Basically follow the two major principles: 1, can be casually read, multiple goroutine at the same time read. 2. When writing, nothing can be done. You can't read or write. A read-write lock is a mutex for read and write operations. The biggest difference between it and a common mutex is that it can be locked and unlocked for both read and write operations. The access control rules that a read-write lock follows differ from the mutex lock. Within the scope of the read-write lock, it allows any read operation to be performed simultaneously. But at the same time, it allows only one write operation to be carried out. And in the course of a write operation being carried out, the read operation is not allowed. This means that there is mutual exclusion between multiple writes under the control of a read-write lock, and the write operation is mutually exclusive to the read operation. However, there is no mutex between multiple read operations. A write lock on a read-write lock that has been written locked will cause the current goroutine to block until the read-write lock is written and unlocked. Of course, if more than one goroutine is blocked, then only one of the goroutine runs will be restored when the corresponding write unlock is carried out. Similarly, a read lock on a read-write lock that has been written locked will also block the corresponding goroutine. But the difference is that once the read-write lock is written to unlock, all goroutine that are blocked by the read lock will be restored. On the other hand, if the current read-write lock is found to be read-locked during the process, the write-lock operation will wait until all read locks that are applied to that read-write lock are cleared. Similarly, when there are multiple write lock operations waiting for this, the full purge of the corresponding read lock only allows one of the write lock operations to get the chance to proceed. Now pay attention to write unlock and read unlock. If a write-lock is written to unlock a read-write lock, a run-time panic is raised. Similarly, a run-time panic is triggered when a read-write lock that is not read-locked reads and unlocks. The write unlock will attempt to wake up all goroutine that are blocked by the read lock. While the read unlock is in progress, it attempts to wake up a goroutine that is blocked by a write lock. Regardless of whether the lock is for a write or read operation, we should try to unlock the corresponding lock in a timely manner. For write unlock, we don't have to say much. and the timely reading and unlocking is often more easily overlooked by us. Although the read unlock does not have any effect on other in-progress read operations, it is closely related to the corresponding write lock. Note that for the same read-write lock, there can be more than one read lock applied to it. Therefore, only if we have the same number of read Unlock for the mutex, can a corresponding write lock be given the opportunity to proceed. Otherwise, the latter will continue to cause the goroutine to be in a blocking state. Due to sync. Rwmutex and *sync. There is no corresponding method for the Rwmutex type to get the number of read locks already in progress, so this is a very easy problem. Fortunately, we can use the defer statement to try to avoid this kind of problem. Keep in mind that write locks and read locks are mutually exclusive for the same read-write lock. Whether it is a write-unlock or a read-unlock, the failure of the operation will negatively affect the normal execution of the process using the read-write lock. In addition to the two pairs of methods that we explained in detail earlier, *sync. The Rwmutex type also has a different method--rlocker. This rlocker method returns a value that implements the Sync.locker interface. Sync. The locker interface type contains two methods, namely: Lock and Unlock. The attentive reader may find that *sync. The mutex type and *sync. The Rwmutex type is the implementation type of the interface type. In fact, we're calling *sync. The resulting value after the Rlocker method of the Rwmutex type value is the value itself. However, the lock method and the Unlock method of the result value correspond to the read lock operation and read unlock operation for the read-write lock respectively. In other words, when we call the lock method or the Unlock method for the result value of a read-write lock's Rlocker method, it is actually the Rlock method or Runlock method that invokes the read-write lock. This is not a difficult operation to implement. IWe can also easily write the implementation of these methods. The practical significance of obtaining such a result value through the Rlocker method of the read-write lock is that we can then manipulate the "write lock" and "read lock" in the read-write lock in the same way. This facilitates flexible adaptation and replacement of related operations.