Question

I am now testing std::condition_variable recently , and find it is quite different with pthread_cond_t after test , I like to know if anything in my test wrong ? or std::condition_variable is really quite different with pthread_cond_t ?

The pthread_cond_t source is the following , compiled at 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) ;
}

The output :

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)

Look like comsumer thread block in pthread_cond_wait , so that "receving" only print one time !!!!

and then the following test is for std::condition_variable !!!!

The following binsem.hpp comes from https://gist.github.com/yohhoy/2156481
with a little modification , compiled at 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_;
}; 

and my source :

#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) ;
}

The output :

i am out
10in f5
9in f5
8in f5
7in f5
6in f5
5in f5
4in f5
3in f5
2in f5
1in f5
(10)

Look like signal only effect if the pthread_cond_wait is waiting!! if not , signal is losted !!

And for std::condition_variable , look like std::condition_variable.wait() will wake up the times notify_one() are called ,if you call notify_one() 10 seconds ago and then call wait() , std::condition_variable.wait() still will get that notify_one() message , quite different with pthread_cond_t !!

Am I miss something in this test ? Or just like my test , std::condition and pthread_cond_t just act like the test showes ?

Edit :

I think the following will showes more easier for this test , sorry to forget to unlock so that the test failed , they are the same behavior !!!!

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") ;
}

This will showes :

sending signal...
wait pass through

And for 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 ;

} 

Will showes :

going sleep
lock pass through

So it is my fault to do the test wrong , cause to deadlock !!! Thanks for all great advice!

Was it helpful?

Solution

In your pthread code, you never unlock the mutex, The consumer() function deadlocks on the second iteration. Also, the outer while loop should break out when some condition is satisfied. I suggest that it should break out when icnt reaches the LOOPCNT. This sort of matches how you break the loop in 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) ;
}

It doesn't seem like your std::thread version of the code closely matches the pthread version at all, so I don't think you can compare their executions in this way. Instead of mimicking a semaphore, I think it better to just use the std::condition_variable exactly like you use it in the pthread version of the code. This way, you can really compare apples to apples.

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) ;
}

OTHER TIPS

Both pthread_cond_t and std::condition_variable work the same way. They are stateless and a signal can only get "lost" if no thread is blocked, in which case no signal is needed because there is no thread that needs one.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top