用C++实现一个二进制信号量类
Implementing a binary semaphore class in C++
所以,我正在我的一个类中开发一个调度器。基本上,我们假设一次只能执行一个线程。我们应该使用一个信号量类来允许这些线程阻塞自己,以模拟等待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);
}
}
您忽略了锁定互斥对象。
其次,这里有一个计数信号量,而不是二进制信号量。二进制信号量只有两种状态,因此bool
变量是合适的:
class Semaphore {
private:
bool signaled; // <- changed
pthread_mutex_t m;
pthread_cond_t c;
void Lock() { pthread_mutex_lock(&m); } // <- helper inlines added
void Unlock() { pthread_mutex_unlock(&m); }
public:
/* -- CONSTRUCTOR/DESTRUCTOR */
Semaphore(bool);
//~Semaphore();
/* -- SEMAPHORE OPERATIONS */
void P(); // changed to void: you don't return anything
void V();
};
Impl:
// consider using C++ constructor initializer syntax.
Semaphore::Semaphore(bool s){ // don't use leading underscores on identifiers
signaled = s;
c = PTHREAD_COND_INITIALIZER; // Not sure you can use the initializers this way!
m = PTHREAD_MUTEX_INITIALIZER; // they are for static objects.
// pthread_mutex_init(&m); // look, this is shorter!
}
void Semaphore::P(){
Lock(); // added
while (!signaled){ // this must be a loop, not if!
pthread_cond_wait(&c, &m);
}
signaled = false;
Unlock();
}
void Semaphore::V(){
bool previously_signaled;
Lock();
previusly_signaled = signaled;
signaled = true;
Unlock(); // always release the mutex before signaling
if (!previously_signaled)
pthread_cond_signal(&c); // this may be an expensive kernel op, so don't hold mutex
}
计数信号量算法缺少while循环,并且不必要地向信号量发出信号。
原始逻辑,添加了锁(见其他答案):
int Semaphore::P(){
Lock();
if(value <= 0){
pthread_cond_wait(&c, &m);
}
value--;
Unlock();
}
int Semaphore::V(){
Lock();
value++;
if(value > 0){
pthread_cond_signal(&c);
}
Unlock();
}
正确的方式:
int Semaphore::P(){
Lock();
while (value <= 0){ // not if
pthread_cond_wait(&c, &m);
}
// value is now > 0, guaranteed by while loop
value--;
// value is now >= 0
Unlock();
}
int Semaphore::V(){
Lock();
int prior_value = value++;
Unlock();
// E.g. if prior_value is 50, should we signal? Why?
if (prior_value == 0) // was not signaled previously, now is.
pthread_cond_signal(&c);
}
为了提高效率,收集关于是否在互斥体内部发出信号的信息,然后在互斥体外部发出信号。互斥应该保留在尽可能少的机器指令上,因为它们会增加争用,减少并发性。信号操作可能需要数百个周期(到内核进行等待队列操作)。
在等待条件变量时必须使用循环,因为可能会出现虚假的唤醒。此外,若您在互斥锁之外发出信号,则条件信号并不总是到达"预期"线程。在unlock
和signal
之间,一些线程可以偷偷进入并调用P
并减少互斥。然后,在这种情况下醒来的人必须重新评估测试,否则将错误地进行测试。
相关文章:
- 将XSD文件嵌入一个(二进制文件)中
- 从一个二进制文件中读取信息,并写入另一个二进制文件
- 将 tesseract 编译/捆绑为一个二进制文件
- 如何将所有依赖项和共享库编译为一个二进制文件
- 如何用C++在windows上制作一个二进制兼容的动态库
- C 打开一个二进制文件
- 在 Google 的C++测试框架中为多个单元测试创建一个二进制文件
- 我可以为一个包含向量的C++结构写一个二进制吗
- 我试图证明一个给定的树是一个二进制搜索树.我将输入一个二叉树,我只想让函数返回true
- 构建一个二进制字符串c++
- 铬嵌入框架(C++)和另一个二进制之间的IPC
- 从一个二进制树复制到另一个
- c++将一个文件读入一个结构并写入一个二进制文件
- 找到与另一个二进制模式匹配的所有 2 位值,然后对它们求和
- 用C++实现一个二进制信号量类
- 将4位写入到一个二进制文件中,其中包含ofstream
- 创建一个二进制文件,向其中添加信息,并从中读取所有记录(电话簿)
- C++用另一个二进制文件编辑二进制文件
- 找出(在c++中)二进制数是否是另一个二进制数的前缀
- 用c++中的映像创建一个二进制文件