信号量入门:解析基本同步模式

5星 · 超过95%的资源 需积分: 9 72 下载量 113 浏览量 更新于2024-08-02 2 收藏 820KB PDF 举报
"《信号量小书》是Allen B. Downey所著,第二版修订于2007年,该书深入浅出地讲解了信号量在并发编程中的应用。书中通过大量的实例来阐述同步问题,涉及的概念包括执行模型、消息序列化、非确定性、共享变量以及并发写入和更新等。书中详细介绍了信号量的定义、语法和作用,并展示了基本的同步模式,如信号、rendezvous、互斥锁、多路复用、屏障、可重用屏障、队列和FIFO队列等。此外,还讨论了一些经典的同步问题,如生产者-消费者问题和读者-写者问题。" 《信号量小书》是针对并发编程领域的一本经典读物,主要关注如何使用信号量来解决进程间的同步问题。信号量是一种用于控制多个进程对共享资源访问的机制,是操作系统设计中至关重要的概念。 1. **同步**:在并发环境中,同步是指控制不同进程之间的执行顺序,确保它们正确地交互和共享资源,避免数据竞争和死锁等问题。 2. **执行模型**:书中提到的执行模型描述了并发进程中线程如何交替执行,这涉及到操作系统调度策略以及并发执行的抽象表示。 3. **消息序列化**:通过消息传递实现进程间通信,以确保操作的有序性,防止数据不一致。 4. **非确定性**:并发环境下,由于线程调度的不确定性,可能导致程序执行的不同结果,这是并发编程中的一大挑战。 5. **共享变量**:多个进程可以同时访问的变量,共享变量的并发写入和更新是并发编程中的核心问题,需要通过同步机制来解决。 6. **信号量**:信号量是一种同步原语,用于控制对共享资源的访问。它有整数值,进程可以进行等待(如果值为0)或信号操作(增加值)。 7. **基本同步模式**:书中详细讲解了信号量在各种场景下的应用,如: - **信号**:一个进程等待另一个进程的信号,以继续执行。 - **rendezvous**:两个进程在特定点会合,完成一次交互。 - **互斥锁**(mutex):确保只有一个进程能访问资源,防止并发写入。 - **多路复用**:允许多个进程等待同一资源,但只允许一个进程获得。 - **屏障**:所有进程到达屏障后一起继续,防止进程提前执行。 - **可重用屏障**:类似于屏障,但可以重复使用,处理多次同步需求。 - **队列**:线程按照先进先出(FIFO)原则等待资源。 8. **经典同步问题**:书中讨论了生产者-消费者问题和读者-写者问题,这些都是并发编程中常见的挑战,需要巧妙地使用信号量来解决。 这本书通过实例和解决方案,帮助读者理解和掌握如何利用信号量来编写正确的并发代码,解决实际的同步问题,对于学习和理解操作系统原理以及并发编程具有很高的价值。

The Sleeping Teaching Assistant A university computer science department has a teaching assistant (TA) who helps undergraduate students with their programming assignments during regular office hours. The TA’s office is rather small and has room for only one desk with a chair and computer. There are three chairs in the hallway outside the office where students can sit and wait if the TA is currently helping another student. When there are no students who need help during office hours, the TA sits at the desk and takes a nap. If a student arrives during office hours and finds the TA sleeping, the student must awaken the TA to ask for help. If a student arrives and finds the TA currently helping another student, the student sits on one of the chairs in the hallway and waits. If no chairs are available, the student will come back at a later time. Using POSIX threads, mutex locks, and/or semaphores, implement a solution that coordinates the activities of the TA and the students. Details for this assignment are provided below. Using Pthreads, begin by creating N students. Each will run as a separate thread. The TA will run as a separate thread as well. Student threads will alternate between programming for a period of time and seeking help from the TA. If the TA is available, they will obtain help. Otherwise, they will either sit in a chair in the hallway or, if no chairs are available, will resume programming and will seek help at a later time. If a student arrives and notices that the TA is sleeping, the student must notify the TA using a semaphore. When the TA finishes helping a student, the TA must check to see if there are students waiting for help in the hallway. If so, the TA must help each of these students in turn. If no students are present, the TA may return to napping. Perhaps the best option for simulating students programming—as well as the TA providing help to a student—is to have the appropriate threads sleep for a random period of time using the sleep() API:

2023-06-04 上传

优化这段代码 #include <iostream> #include <thread> #include <chrono> #include <mutex> #include <semaphore.h> using namespace std; // shared data resource int shared_data = 0; // semaphores for synchronization sem_t mutex, rw_mutex; // number of readers int num_readers = 0; // reader function void reader(int id) { while (true) { // acquire mutex to update the number of readers sem_wait(&mutex); num_readers++; if (num_readers == 1) { // if this is the first reader, acquire the rw_mutex sem_wait(&rw_mutex); } sem_post(&mutex); // read the shared data cout << "Reader " << id << " read shared data: " << shared_data << endl; // release mutex sem_wait(&mutex); num_readers--; if (num_readers == 0) { // if this is the last reader, release the rw_mutex sem_post(&rw_mutex); } sem_post(&mutex); // sleep for a random amount of time this_thread::sleep_for(chrono::milliseconds(rand() % 1000)); } } // writer function void writer(int id) { while (true) { // acquire the rw_mutex sem_wait(&rw_mutex); // write to the shared data shared_data++; cout << "Writer " << id << " wrote to shared data: " << shared_data << endl; // release the rw_mutex sem_post(&rw_mutex); // sleep for a random amount of time this_thread::sleep_for(chrono::milliseconds(rand() % 1000)); } } int main() { // initialize semaphores sem_init(&mutex, 0, 1); sem_init(&rw_mutex, 0, 1); // create reader threads thread readers[8]; for (int i = 0; i < 8; i++) { readers[i] = thread(reader, i); } // create writer threads thread writers[2]; for (int i = 0; i < 2; i++) { writers[i] = thread(writer, i); } // join threads for (int i = 0; i < 8; i++) { readers[i].join(); } for (int i = 0; i < 2; i++) { writers[i].join(); } // destroy semaphores sem_destroy(&mutex); sem_destroy(&rw_mutex); return 0; }

2023-05-25 上传