我现在正在测试std :: condition_variable,并且在测试后发现它与pthread_cond_t完全不同,我想知道我的测试中是否有任何错误?或std :: condition_variable与pthread_cond_t真的完全不同?
pthread_cond_t源代码如下,在gcc 4.4.6中编译:
pthread_cond_t condA = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int ProcessRow = 0 ;
#define LOOPCNT 10
void *producer()
{
int idx ;
for(idx=0;idx<LOOPCNT;idx++)
{
//pthread_mutex_lock(&mutex);
__sync_add_and_fetch(&ProcessRow,1) ;
pthread_cond_signal(&condA);
printf("sending signal...(%d)\n",ProcessRow) ;
//pthread_mutex_unlock(&mutex);
}
printf("I am out ... \n") ;
}
void *consumer()
{
int icnt = 0 ;
while(1)
{
pthread_mutex_lock(&mutex);
while (ProcessRow <= 0)
pthread_cond_wait(&condA, &mutex);
pthread_mutex_unlock(&mutex); // I forget to add unlock to fail this test
__sync_sub_and_fetch(&ProcessRow,1) ;
++icnt ;
printf("receving=(%d)\n",ProcessRow) ;
usleep(10000) ;
}
printf("(%d)\n",ProcessRow) ;
}
输出:
sending signal...(1)
sending signal...(2)
sending signal...(3)
sending signal...(4)
sending signal...(5)
sending signal...(6)
sending signal...(7)
sending signal...(8)
sending signal...(9)
sending signal...(10)
I am out ...
receving=(9)
在pthread_cond_wait中看起来像comsumer线程块,因此“receving”只打印 一次!!!!
然后以下测试用于std :: condition_variable !!!!
以下binsem.hpp来自
https://gist.github.com/yohhoy/2156481
稍加修改,编译为g ++ 4.8.1
class binsem {
public:
explicit binsem(int init_count = count_max)
: count_(init_count) {}
// P-operation / acquire
void wait()
{
std::unique_lock<std::mutex> lk(m_);
cv_.wait(lk, [this]{ return 0 < count_; });
--count_;
}
bool try_wait()
{
std::lock_guard<std::mutex> lk(m_);
if (0 < count_)
{
--count_;
return true;
} else
{
return false;
}
}
// V-operation / release
void signal()
{
std::lock_guard<std::mutex> lk(m_);
//if (count_ < count_max) // I mark here
//{ // I mark here
++count_;
cv_.notify_one();
//} // I mark here
}
// Lockable requirements
void lock() { wait(); }
bool try_lock() { return try_wait(); }
void unlock() { signal(); }
private:
static const int count_max = 1;
int count_;
std::mutex m_;
std::condition_variable cv_;
};
和我的来源:
#define LOOPCNT 10
atomic<int> ProcessRow ;
void f4()
{
for(int i=0;i<LOOPCNT;i++)
{
sem2.unlock() ;
++ProcessRow ;
}
cout << "i am out" << endl ;
}
void f5()
{
int icnt = 0 ;
std::chrono::milliseconds sleepDuration(1000);
while(1)
{
sem2.lock() ;
++icnt ;
std::this_thread::sleep_for(sleepDuration);
cout << ProcessRow << "in f5 " << endl ;
--ProcessRow ;
if(icnt >= LOOPCNT)
break ;
}
printf("(%d)\n",icnt) ;
}
输出:
i am out
10in f5
9in f5
8in f5
7in f5
6in f5
5in f5
4in f5
3in f5
2in f5
1in f5
(10)
如果pthread_cond_wait正在等待,看起来只有信号效果!如果没有,信号就会丢失!!
对于std :: condition_variable,看起来像std :: condition_variable.wait()将唤醒notify_one()被调用的次数,如果你在10秒前调用notify_one()然后调用wait(),std :: condition_variable.wait()仍会得到那个notify_one()消息,与pthread_cond_t完全不同!!
我在这次考试中错过了什么?或者就像我的测试一样,std :: condition和pthread_cond_t就像测试showes一样?
编辑:
我认为以下内容对于此测试会更容易显示,抱歉忘记解锁以便测试失败,它们是相同的行为!!!!
int main()
{
//pthread_mutex_lock(&mutex);
++ProcessRow ;
pthread_cond_signal(&condA);
//pthread_mutex_unlock(&mutex);
printf("sending signal...\n") ;
sleep(10) ;
pthread_mutex_lock(&mutex);
while (ProcessRow <= 0)
pthread_cond_wait(&condA, &mutex);
pthread_mutex_unlock(&mutex);
printf("wait pass through\n") ;
}
这将显示:
sending signal...
wait pass through
对于std :: condition_variable
int main()
{
sem2.unlock() ;
std::chrono::milliseconds sleepDuration(10000);
cout << "going sleep" << endl ;
std::this_thread::sleep_for(sleepDuration);
sem2.lock() ;
cout << "lock pass through " << endl ;
}
将表示:
going sleep
lock pass through
所以测试错误是我的错,导致僵局!谢谢你提出的所有好建议!
答案 0 :(得分:2)
pthread_cond_t和std :: condition_variable都以相同的方式工作。它们是无状态的,如果没有线程被阻塞,信号只能“丢失”,在这种情况下不需要信号,因为没有线程需要一个。
答案 1 :(得分:2)
在你的pthread代码中,你永远不会解锁互斥锁,第二次迭代时consumer()
函数死锁。此外,当满足某些条件时,外部while
循环应该会中断。我建议在icnt
到达LOOPCNT
时突然爆发。这类与你在f5()
中打破循环的方式相匹配。
void *consumer(void *x)
{
int icnt = 0 ;
while(1)
{
pthread_mutex_lock(&mutex);
while (ProcessRow <= 0)
pthread_cond_wait(&condA, &mutex);
__sync_sub_and_fetch(&ProcessRow,1) ;
++icnt ;
printf("receving=(%d) icnt=(%d)\n",ProcessRow, icnt) ;
pthread_mutex_unlock(&mutex);
if (icnt == LOOPCNT) break;
usleep(10000) ;
}
printf("(%d)\n",ProcessRow) ;
}
您的std::thread
版本的代码似乎与pthread版本完全匹配,所以我认为您不能以这种方式比较它们的执行情况。而不是模仿信号量,我认为最好只使用std::condition_variable
,就像在代码的pthread版本中使用它一样。通过这种方式,您可以真正地比较苹果和苹果。
std::condition_variable condA;
std::mutex mutex;
volatile int ProcessRow = 0 ;
#define LOOPCNT 10
void producer()
{
int idx ;
for(idx=0;idx<LOOPCNT;idx++)
{
std::unique_lock<std::mutex> lock(mutex);
__sync_add_and_fetch(&ProcessRow,1) ;
condA.notify_one();
printf("sending signal...(%d)\n",ProcessRow) ;
}
printf("I am out ... \n") ;
}
void consumer()
{
int icnt = 0 ;
while(icnt < LOOPCNT)
{
if(icnt > 0) usleep(10000);
std::unique_lock<std::mutex> lock(mutex);
while (ProcessRow <= 0)
condA.wait(lock);
__sync_sub_and_fetch(&ProcessRow,1) ;
++icnt ;
printf("receving=(%d) icnt=(%d)\n",ProcessRow, icnt) ;
}
printf("(%d)\n",ProcessRow) ;
}