4

最近 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 の消費者スレッド ブロックのように見えるため、「受信」は 1 回だけ出力されます !!!!

そして、次のテストは 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 の場合、10 秒前に notify_one() を呼び出してから wait() を呼び出すと、 std::condition_variable.wait() が notify_one() が呼び出されたときにウェイクアップするように見えます。 std::condition_variable.wait () はまだその notify_one() メッセージを取得しますが、pthread_cond_t とはまったく異なります!!

私はこのテストで何かを見逃していますか? または、私のテストと同じように、 std::condition と pthread_cond_t は、テストが示すように機能しますか?

編集 :

以下は、このテストをより簡単に示すと思います。ロックを解除するのを忘れてテストが失敗したことをお詫びします。それらは同じ動作です!!!!

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

したがって、テストを間違って行うのは私のせいであり、デッドロックが発生します!!! 素晴らしいアドバイスをありがとう!

4

2 に答える 2

3

pthread コードでは、ミューテックスのロックを解除することはありません。consumer()関数は 2 回目の反復でデッドロックします。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) ;
}
于 2013-08-14T02:43:45.837 に答える