所以,我正在我的一个 class 中安排一个调度程序 . 基本上,我们假装一次只能执行一个线程 . 我们应该使用信号量类来允许这些线程阻塞自己来模拟等待CPU的线程 .
问题是,线程似乎在错误的时间阻塞并在错误的时间执行 . 我想知道我是否缺少对信号量的概念性理解以及如何实现它 . 我想知道我是否能对我的实施得到一些反馈 . 教师提供了这个头文件,我没有以任何方式修改过:
class Semaphore {
private:
int value;
pthread_mutex_t m;
pthread_cond_t c;
public:
/* -- CONSTRUCTOR/DESTRUCTOR */
Semaphore(int _val);
//~Semaphore();
/* -- SEMAPHORE OPERATIONS */
int P();
int V();
};
这是我使用posix东西的实现:
Semaphore::Semaphore(int _val){
value = _val;
c = PTHREAD_COND_INITIALIZER;
m = PTHREAD_MUTEX_INITIALIZER;
}
int Semaphore::P(){
if(value <= 0){
pthread_cond_wait(&c, &m);
}
value--;
}
int Semaphore::V(){
value++;
if(value > 0){
pthread_cond_signal(&c);
}
}
2 回答
你忽略了锁定互斥锁 .
其次,你在这里有一个计数信号量,而不是二进制信号量 . 二进制信号量只有两个状态,因此
bool
变量是合适的:IMPL:
您的计数信号量算法缺少while循环,并且不必要地发信号通知信号量 .
原始逻辑,添加了锁(参见其他答案):
正确的方法:
为了提高效率,请收集有关是否在互斥锁内发出信号的信息,然后在互斥锁外部执行信号 . 互斥体应该尽可能少地保留机器指令,因为它们会增加争用,从而降低并发性 . 信号操作可能需要数百个周期(内核跳转到等待队列操作) .
在等待条件变量时必须使用循环,因为可能会出现虚假的唤醒 . 此外,如果您在互斥锁之外发出信号,则状态信号并不总是转到"intended"线程 . 在
unlock
和signal
之间,某些线程可以潜入并调用P
并减少互斥锁 . 然后在条件上醒来的那个必须重新评估测试,否则它将错误地进行 .