diff --git a/notes/pics/rw-priority-timeline.png b/notes/pics/rw-priority-timeline.png new file mode 100644 index 00000000..b42f343a Binary files /dev/null and b/notes/pics/rw-priority-timeline.png differ diff --git a/notes/计算机操作系统 - 进程管理 - 进阶.md b/notes/计算机操作系统 - 进程管理 - 进阶.md index 512911ca..baf7d7de 100644 --- a/notes/计算机操作系统 - 进程管理 - 进阶.md +++ b/notes/计算机操作系统 - 进程管理 - 进阶.md @@ -13,56 +13,56 @@ 主线见[计算机操作系统 - 进程管理 · 读者-写者问题](计算机操作系统%20-%20进程管理.md#2-读者-写者问题),那里用 count、count_mutex 和 data_mutex 实现的是读者优先:只要还有读者在读,后到的读者可以直接进入,写者要一直等待。 +三种实现的差别可以用同一组到达顺序来比较(按主线和本节的代码逐行模拟,信号量按先进先出的顺序唤醒): + +

+ 以下内容由 [@Bandi Yugandhar](https://github.com/yugandharbandi) 提供。 主线中的实现可能导致写者饥饿。下面的实现是写者优先的:写者进入队列之后,只需要等待在它之前进入的读者,不会被之后到达的读者一直阻塞。 ```c -int readcount, writecount; //(initial value = 0) -semaphore rmutex, wmutex, readLock, resource; //(initial value = 1) +int readcount, writecount; // 初值都为 0 +semaphore rmutex, wmutex, readLock, resource; // 初值都为 1 -//READER void reader() { - - down(&readLock); // reader is trying to enter - down(&rmutex); // lock to increase readcount - readcount++; - if (readcount == 1) - down(&resource); //if you are the first reader then lock the resource - up(&rmutex); //release for other readers - up(&readLock); //Done with trying to access the resource + // 进入 + down(&readLock); // 有写者在排队时,读者在这里被挡住 + down(&rmutex); // 保护 readcount + readcount++; + if (readcount == 1) + down(&resource); // 第一个读者锁住资源,防止写者进入 + up(&rmutex); + up(&readLock); - -//reading is performed + // 读 - - down(&rmutex); //reserve exit section - avoids race condition with readers - readcount--; //indicate you're leaving - if (readcount == 0) //checks if you are last reader leaving - up(&resource); //if last, you must release the locked resource - up(&rmutex); //release exit section for other readers + // 退出 + down(&rmutex); + readcount--; + if (readcount == 0) + up(&resource); // 最后一个读者释放资源 + up(&rmutex); } -//WRITER void writer() { - - down(&wmutex); //reserve entry section for writers - avoids race conditions - writecount++; //report yourself as a writer entering - if (writecount == 1) //checks if you're first writer - down(&readLock); //if you're first, then you must lock the readers out. Prevent them from trying to enter CS - up(&wmutex); //release entry section + // 进入 + down(&wmutex); // 保护 writecount + writecount++; + if (writecount == 1) + down(&readLock); // 第一个写者挡住之后到达的读者 + up(&wmutex); - - down(&resource); //reserve the resource for yourself - prevents other writers from simultaneously editing the shared resource - //writing is performed - up(&resource); //release file + down(&resource); // 写者之间互斥,并等待正在读的读者退出 + // 写 + up(&resource); - - down(&wmutex); //reserve exit section - writecount--; //indicate you're leaving - if (writecount == 0) //checks if you're the last writer - up(&readLock); //if you're last writer, you must unlock the readers. Allows them to try enter CS for reading - up(&wmutex); //release exit section + // 退出 + down(&wmutex); + writecount--; + if (writecount == 0) + up(&readLock); // 最后一个写者放行读者 + up(&wmutex); } ``` @@ -71,55 +71,38 @@ void writer() { 以上两种实现总有一方可能饥饿。下面的实现使用一个先进先出的 serviceQueue 让读者和写者按到达顺序排队,获取共享数据的锁总能在有限时间内完成,因此不会出现饥饿。 ```c -int readCount; // init to 0; number of readers currently accessing resource +int readCount; // 正在读的读者数,初值为 0 +semaphore resourceAccess; // 控制对资源的读写,初值为 1 +semaphore readCountAccess; // 保护 readCount,初值为 1 +semaphore serviceQueue; // 按到达顺序排队,初值为 1,要求按先进先出的顺序唤醒 -// all semaphores initialised to 1 -Semaphore resourceAccess; // controls access (read/write) to the resource -Semaphore readCountAccess; // for syncing changes to shared variable readCount -Semaphore serviceQueue; // FAIRNESS: preserves ordering of requests (signaling must be FIFO) +void writer() { + down(&serviceQueue); // 排队 + down(&resourceAccess); // 等待独占资源 + up(&serviceQueue); // 轮到下一个 -void writer() -{ - down(&serviceQueue); // wait in line to be serviced - // - down(&resourceAccess); // request exclusive access to resource - // - up(&serviceQueue); // let next in line be serviced + writeResource(); // 写 - // - writeResource(); // writing is performed - // - - // - up(&resourceAccess); // release resource access for next reader/writer - // + up(&resourceAccess); } -void reader() -{ - down(&serviceQueue); // wait in line to be serviced - down(&readCountAccess); // request exclusive access to readCount - // - if (readCount == 0) // if there are no readers already reading: - down(&resourceAccess); // request resource access for readers (writers blocked) - readCount++; // update count of active readers - // - up(&serviceQueue); // let next in line be serviced - up(&readCountAccess); // release access to readCount +void reader() { + down(&serviceQueue); // 排队 + down(&readCountAccess); + if (readCount == 0) + down(&resourceAccess); // 第一个读者锁住资源,写者被挡住 + readCount++; + up(&serviceQueue); // 轮到下一个 + up(&readCountAccess); - // - readResource(); // reading is performed - // + readResource(); // 读 - down(&readCountAccess); // request exclusive access to readCount - // - readCount--; // update count of active readers - if (readCount == 0) // if there are no readers left: - up(&resourceAccess); // release resource access for all - // - up(&readCountAccess); // release access to readCount + down(&readCountAccess); + readCount--; + if (readCount == 0) + up(&resourceAccess); // 最后一个读者释放资源 + up(&readCountAccess); } - ``` ## 参考资料