简体   繁体   English

信号量的标准原子操作

[英]Standard atomic operations of semaphores

I am self-learning C, and this is a practice problem on semaphores: 我是自学C,这是信号量的练习题:

Recall that a counting semaphore S is an integer variable that can only be accused via two standard atomic operations, P (probe) and V (signal), as shown in the figure: 回想一下,计数信号量S是一个整数变量,只能通过两个标准原子操作P(探测)和V(信号)来控制,如图所示:

 /*The probe or wait operation */ P(S) { while(S <= 0); // do nothing S--; } /*The signal operation */ V(S) { S++; } 

The value of a counting semaphore can range over an unrestricted domain of integers (that is, the semaphore can hold an arbitrary value) whereas the value of a binary semaphore can only be 0 or 1. Show how counting semaphores can be implemented using only binary semaphores, and ordinary (that is, preemptible) machine instructions and data structures. 计数信号量的值可以超过不受限制的整数域(即,信号量可以包含任意值),而二进制信号量的值只能是0或1.显示如何仅使用二进制来实现计数信号量信号量和普通(即可抢占)机器指令和数据结构。

Provide the pseudocode for the P and V operations. 为P和V操作提供伪代码。

I found a related answer to this online: 我在网上找到了相关的答案:

struct semaphore {                                                        
    int value;                                                            
    queue L; // l list of processes                                       
}                                                                         

wait(S) {                                                                 

    if(s.value > 0){                                                      
        s.value = s.value - 1;                                            
    } else {                                                              
        add this process to S.L;                                          
        block;                                                            
    }                                                                     
}                                                                         

signal(S){                                                                

    if(S.L != EMPTY) {                                                    
        remove a process P from S.L;                                      
        wakeup(P);                                                        
    } else {                                                              
        s.value = s.value + 1;                                            
    }                                                                     
} 

But to be honest, I have no idea what it's trying to do. 但说实话,我不知道它在做什么。 I would really appreciate it someone could explain the answer, or perhaps demonstrate in pseudo-code on how to answer this. 我真的很感激有人可以解释答案,或者可能用伪代码演示如何回答这个问题。

Show how counting semaphores can be implemented using only binary semaphores, and ordinary (that is, preemptible) machine instructions and data structures. 展示如何仅使用二进制信号量和普通(即可抢占的)机器指令和数据结构来实现计数信号量。

A binary semaphore is pretty much like a mutex (there are some remarkable differences, but for the purposes of this problem assume they are equivalent), and as such you can implement a generic semaphore with a data structure that has a counter and a binary semaphore. 二进制信号量非常像互斥体(存在一些显着的差异,但出于这个问题的目的,假设它们是等价的),因此您可以实现具有计数器和二进制信号量的数据结构的通用信号量。 The binary semaphore is used to synchronize access to the counter. 二进制信号量用于同步对计数器的访问。

Signaling can be implemented by acquiring the binary semaphore (ie waiting on the semaphore), incrementing the counter and then signaling the binary semaphore (to release the lock). 信令可以通过获取二进制信号量(即等待信号量),递增计数器然后发信号通知二进制信号量(释放锁定)来实现。

Waiting is implemented by repeatedly acquiring the lock (waiting on the binary semaphore), testing if the counter is greater than 0, and releasing the lock. 通过重复获取锁(等待二进制信号量),测试计数器是否大于0以及释放锁来实现等待。 If the counter is indeed greater than 0, then it means we got a place in line, so we decrement the counter and return. 如果计数器确实大于0,那么这意味着我们得到了一个位置,所以我们递减计数器并返回。 Note that this must be atomic: we can't release the binary semaphore and decrement the counter afterwards, since that would open up a window of time where another thread could mistakenly see the same thing and acquire our place in the line at the same time. 请注意,这必须是原子的:我们不能释放二进制信号量并在之后递减计数器,因为这会打开一个时间窗口,其中另一个线程可能会错误地看到相同的东西并同时获取我们在该行中的位置。 So, the binary semaphore is used to atomically test the counter and decrement it (if it is greater than 0). 因此,二进制信号量用于原子测试计数器并减少它(如果它大于0)。

Assume a binary semaphore has type bin_sem_t . 假设二进制信号量具有类型bin_sem_t Here's some code that illustrates this. 这里有一些代码可以说明这一点。 The data structure is as follows: 数据结构如下:

/* A semaphore implemented with a binary semaphore */
struct semaphore {
    bin_sem_t sem; /* Controls concurrent access to the counter */
    int counter;
};

Signaling: 信号:

void sem_signal(struct semaphore *semaphore) {
    /* We use the binary semaphore to atomically increment the counter */
    wait(semaphore->sem);
    semaphore->counter++;
    signal(semaphore);
}

Waiting: 等候:

void sem_wait(struct semaphore *semaphore) {
    int acquired = 0;
    /* Here we use the binary semaphore to atomically test and
     * decrement the counter
     */
    while (!acquired) {
        wait(semaphore->sem);
        if (semaphore->counter > 0) {
            semaphore->counter--;
            acquired = 1;
        }
        signal(semaphore->sem);
    }
}

Some important notes: 一些重要的说明:

  • The code assumes there is an initialization function that properly sets the counter to 0 and initializes the binary semaphore before any of the calls to either sem_signal() or sem_wait() take place. 该代码假定存在一个初始化函数,该函数将计数器正确设置为0,并在发生对sem_signal()sem_wait()任何调用之前初始化二进制信号量。
  • This implementation uses ordinary machine instructions, as the question stated. 正如所述问题,该实现使用普通的机器指令。 Note that it keeps looping until there is a "place in line". 请注意,它会一直循环,直到存在“排成一行”。 It's like having an annoying travel companion repeatedly asking "Are we there yet?". 这就像有一个讨厌的旅行伙伴一再问“我们还在吗?”。 Not nice at all. 一点都不好。 This is known as polling , and it's bad because it wastes CPU cycles. 这称为轮询 ,这很糟糕,因为它会浪费CPU周期。 Keep in mind that in the real world semaphores are not implemented like this; 请记住,在现实世界中,信号量不是这样实现的; instead, processes are put to sleep and made runnable only when the semaphore is vacant. 相反,只有当信号量空缺时,进程才会进入休眠状态并且可以运行。

To be honest, I don't think the answer you found online is correct, it doesn't seem to have any form of synchronization on the counter or on the processes queue. 说实话,我不认为你在网上找到的答案是正确的,它似乎没有在柜台或进程队列上进行任何形式的同步。 So, it fails to address one of the core concerns when implementing synchronization primitives: obviously, they have to be thread-safe! 因此,在实现同步原语时,它无法解决其中一个核心问题:显然,它们必须是线程安全的!

This doesn't look right either: 这看起来也不正确:

The value of a counting semaphore can range over an unrestricted domain of integers (that is, the semaphore can hold an arbitrary value) [...] 计数信号量的值可以超过不受限制的整数域(也就是说,信号量可以保持任意值)[...]

First of all, a generic semaphore typically can't have negative values, it is always greater than or equal to 0. Second, there is an obvious upper limit on the value of a counter; 首先,通用信号量通常不能具有负值,它总是大于或等于0.其次,计数器的值有一个明显的上限; computers don't have infinite memory. 电脑没有无限的记忆。 In Linux, the maximum value a semaphore can hold is defined as SEM_VALUE_MAX in semaphore.h . 在Linux中,信号量可以容纳的SEM_VALUE_MAXsemaphore.h定义为SEM_VALUE_MAX

So please be careful with these online tutorials, most of them are either inaccurate, lack in detail, or are just plain wrong. 所以请注意这些在线教程,其中大部分都是不准确的,缺乏细节,或者只是完全错误。 You should learn from a good book. 你应该从一本好书中学习。 I usually like to recommend Advanced Programming in the UNIX Environment , although it is not specifically about threads, but it covers synchronization primitives in great depth. 我通常喜欢在UNIX环境中推荐高级编程 ,虽然它不是专门针对线程的,但是它深入介绍了同步原语。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM