使用互斥操作和基元实现信号量

时间:2013-12-12 04:00:21

标签: c++ c++11 mutex semaphore

前段时间接受采访并被要求实施 信号量仅通过使用互斥操作和基元 (他允许int被视为原子)。我在下面找到了解决方案。 他不喜欢忙/等待部分 - while (count >= size) {} - 并且要求通过使用更原始的方式来实现锁定 类型和互斥体。我无法提供改进的解决方案。 有什么想法可以做到吗?

struct Semaphore {
int size;
atomic<int> count;
mutex updateMutex;

Semaphore(int n) : size(n) { count.store(0); }

void aquire() {
    while (1) {
        while (count >= size) {}
        updateMutex.lock();
        if (count >= size) {
            updateMutex.unlock();
            continue;
        }
        ++count;
        updateMutex.unlock();
        break;
    }
}

void release() {
    updateMutex.lock();
    if (count > 0) {
        --count;
    } // else log err
    updateMutex.unlock();
}
};

4 个答案:

答案 0 :(得分:2)

我敢打赌,如果没有忙碌循环仅使用互斥锁,就无法实现。

如果没有忙碌循环,你必须阻止某个地方。你得到的唯一阻塞原语是 一个互斥体。因此,当信号量计数器为零时,您必须阻止某些互斥锁。您可以仅由该互斥锁的单个所有者唤醒。但是,只要任意线程向信号量返回一个计数器,会被唤醒。

现在,如果允许条件变量,那就完全不同了。

答案 1 :(得分:2)

编辑 - 使用第二个互斥锁进行排队而不是线程

由于互斥锁已经具有适当的线程支持,因此它可以用于对线程进行排队(而不是像我第一次尝试那样明确地执行它)。 除非,互斥锁仅限于让所有者解锁( lock ?),否则此解决方案无效。

我在Anthony Howe's pdf找到了搜索时遇到的解决方案。还有两个解决方案。为了这个例子,我更改了名称以使其更有意义。

或多或少的伪代码:

Semaphore{
    int n;
    mutex* m_count;         //unlocked initially
    mutex* m_queue;         //locked initially
};

void wait(){
    m_count.lock();
    n = n-1;
    if(n < 0){
        m_count.unlock();
        m_queue.lock();     //wait
    }
    m_count.unlock();       //unlock signal's lock
}

void signal(){
    m_count.lock();
    n = n+1;

    if(n <= 0){
        m_queue.unlock();   //leave m_count locked
    }
    else{
        m_count.unlock();
    }
}

答案 2 :(得分:0)

作为@chill pointet,我在这里写下的解决方案将无效,因为锁具有独特的所有权。我想最后你将恢复忙等待(如果你不允许使用条件变量)。如果ppl,我把它留在这里。我们有同样的想法,他们认为这不起作用;)

struct Semaphore {
int size;
atomic<int> count;
mutex protection;
mutex wait;

Semaphore(int n) : size(n) { count.store(0); }

void aquire() {
    protection.lock();
    --count;
    if (count < -1) {
        protection.unlock();
        wait.lock();
    }
    protection.unlock();
}

void release() {
    protection.lock();
    ++count;
    if (count > 0) {
        wait.unlock();
    }
    protection.unlock();
}
};

答案 3 :(得分:-2)

lemme试试这个

`

# number of threads/workers
w = 10
# maximum concurrency
cr = 5
r_mutex = mutex()
w_mutex = [mutex() for x in range(w)]

# assuming mutex can be locked and unlocked by anyone 
# (essentially we need a binary semaphore)

def acquire(id):

    r_mutex.lock()
    cr -= 1
    # r_mutex.unlock()
    
    # if exceeding maximum concurrency
    if cr < 0:
        # lock twice to be waken up by someone
        w_mutex[id].lock()
        r_mutex.unlock()
        w_mutex[id].lock()
        w_mutex[id].unlock()
        return

    r_mutex.unlock()

    
    
       
def release(id):

    r_mutex.lock()
    cr += 1
    # someone must be waiting if cr < 0
    if cr <= 0:
        # maybe you can do this in a random order
        for w in w_mutex:
            if w.is_locked():
                w.unlock()
                break
    r_mutex.unlock()

`