59 lines
3.3 KiB
Markdown
59 lines
3.3 KiB
Markdown
## rwmutex
|
||
|
||
[sync.RWMutex](https://golang.org/pkg/sync/#RWMutex) -- это примитив синхронизации,
|
||
предоставляющий доступ к критической секции произвольному количеству читателей и
|
||
не более, чем одному писателю. При этом, если есть писатель, то читателей нет.
|
||
|
||
### Что нужно сделать?
|
||
|
||
Нужно написать реализацию RWMutex, используя каналы.
|
||
|
||
Использование пакета [sync](https://golang.org/pkg/sync) в этой задаче запрещено!
|
||
|
||
```go
|
||
type RWMutex struct {}
|
||
|
||
func (rw *RWMutex) Lock() {}
|
||
func (rw *RWMutex) Unlock() {}
|
||
|
||
func (rw *RWMutex) RLock() {}
|
||
func (rw *RWMutex) RUnlock() {}
|
||
```
|
||
|
||
`RWMutex` можно представлять себе как две блокировки, блокировка на чтение и блокировка на запись.
|
||
|
||
`New()` возвращает `RWMutex`, в котором ни одна из блокировок не взята.
|
||
|
||
Процессы, желающие изменить данные (писатели), берут блокировку на запись с помощью метода `Lock`.
|
||
Процессы, желающие прочитать данные (читатели), берут блокировку на чтение с помощью метода `RLock`.
|
||
По окончании записи писатель отпускает блокировку на запись (`Unlock`).
|
||
С блокировкой на чтение связано число активных читателей.
|
||
При взятии блокировки (`RLock`) это число инкрементируется.
|
||
При завершении чтения (`RUnlock`) блокировка на чтение уменьшает счётчик.
|
||
|
||
#### Свойства
|
||
1. Писатель не заблокируется при взятии блокировки только при условии,
|
||
что никакой другой писатель и никакой другой читатель не владеет соответствующей блокировкой.
|
||
2. Если какой-то писатель взял блокировку на запись, любой новый писатель или читатель заблокируется при взятии блокировки.
|
||
3. Если какой-то читатель взял блокировку на чтение, любой новый писатель заблокируется на взятии блокировки.
|
||
Однако любой другой читатель сможет взять блокировку на чтение.
|
||
|
||
Для выполнения этих свойств достаточно двух каналов.
|
||
|
||
#### Активное ожидание
|
||
|
||
Ваше решение не должно использовать активное ожидание. Активное ожидание (busy wait)
|
||
это ситуация, когда заблокированная горутина проверяет условие в вечном цикле. Например:
|
||
|
||
```go
|
||
func (wg *WaitGroup) Wait() {
|
||
for {
|
||
wg.lock <- struct{}{}
|
||
if wg.ch1 == 0 {
|
||
<-wg.lock
|
||
return
|
||
}
|
||
<-wg.lock
|
||
}
|
||
}
|
||
```
|