对于Mutex和Semaphore这两种机制最多的解释为:
- Mutex:用于线程间的互斥
- Semaphore:用于线程间的同步
这个定义很准确,然而,在经典生产者消费者模型中却经常出现mutex滥用的例子,例如这样场景:一个生产者,一个消费者,多块缓存:buffer[BUFFER_SIZE],很多网上的实现为:
Semaphore s_full(0);
Sempahore s_empty(BUFFER_SIZE):
Mutex mutex;
int in_idx=0;
int out_idx=0;
<生产者>
while(true)
{
s_empty.unsignal();
mutex.lock();
buffer.put(in_idx);
in_idx = (in_idx + 1)%BUFFERIZE;
mutex.unlock();
s_full.signal();
}
<消费者>
while(true)
{
s_full.unsignal();
mutex.lock();
buffer.get(out_idx);
out_idx = (out_idx + 1)%BUFFERIZE;
mutex.unlock();
s_empty.signal();
}
其实代码逻辑上没错,但是mutex却是多余的,注意场景中semaphore的控制决定了两个线程不会同时操作同一处缓存,也就是说按照代码对buffer的访问并不需要互斥。另两种场景:一个buffer,一个生产者,一个消费者或者一个buffer,多个生产者,多个消费者这时也是不需要使用mutex互斥的。
但是:像 多个buffer,多个生产者,多个消费者 的情况,却需要对buffer互斥访问,如果是多个buffer,实际上就是需要保证对in_idx和out_idx的互斥访问,这种情况下我们可以对in_idx和out_idx的访问(get,set)放置于临界区内,而对buffer的操作(put,get)放置于临界区之外,可以提高并发率。代码如下(From Internet)
Semaphore s_full(0);Sempahore s_empty(BUFFER_SIZE):
Mutex mutex;
int in_idx=0;
int out_idx=0;
int getEmptyIndex()
{
rt = in_idx;
in_idx = (in_idx + 1)%BUFFERIZE;
return rt;
}
int getFullIndex()
{
rt = out_idx;
out_idx = (out_idx + 1)%BUFFERIZE;
return rt;
}
<生产者>
while(true)
{
s_empty.unsignal();
mutex.lock();
crt = getEmptyIndex;
mutex.unlock();
buffer.put(crt);
s_full.signal();
}
<消费者>
while(true)
{
s_full.unsignal();
mutex.lock();
crt = getFullIndex();
mutex.unlock();
buffer.get(crt);
s_empty.signal();
}