前段时间接受采访并被要求实施
信号量仅通过使用互斥操作和基元
(他允许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();
}
};
答案 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()
`