2016-04-10 15 views
-1

このコードは正しいですか?私はこのコードを誰かのブログで見ると、volatileは1人の顧客と1人のプロデューサーだけの環境で安全だと言いました。スレッドセーフなのかどうかはわかりません。揮発性変数は、ある顧客スレッドと1つのプロデューサスレッドで安全ですか?

コードは以下の通りです:

#include <iostream> 
#include <pthread.h> 


template<class QElmType> 
struct qnode 
{ 
    struct qnode *next; 
    QElmType data; 
}; 
template<class QElmType> 
class queue 
{ 
public: 
     queue() {init();} 
     ~queue() {destroy();} 

     bool init() 
     { 
       m_front = m_rear = new qnode<QElmType>; 
       if (!m_front) 
         return false; 
       m_front->next = 0; 
       return true; 
     } 
     void destroy() 
     { 
       while (m_front) 
       { 
         m_rear = m_front->next; 
         delete m_front; 
         m_front = m_rear; 
       } 
     } 
     bool push(QElmType e) 
     { 
       struct qnode<QElmType> *p = new qnode<QElmType>; 
       if (!p) 
         return false; 
       p->next = 0; 
       m_rear->next = p; 
       m_rear->data = e; 
       m_rear = p; 
       return true; 
     } 
     bool pop(QElmType *e) 
     { 
       if (m_front == m_rear) 
         return false; 


       struct qnode<QElmType> *p = m_front; 
       *e = p->data; 
       m_front = p->next; 
       delete p; 
       return true; 
     } 
private: 
    struct qnode<QElmType> * volatile m_front, * volatile m_rear; 
}; 


queue<int> g_q; 


void *thread1(void * l) 
{ 
     int i = 0; 
     while (1) 
     { 
       g_q.push(i); 
       i++; 
       usleep(::rand()%1000); 
     } 
     return 0; 
} 
void *thread2(void * l) 
{ 
     int i; 
     while (1) 
     { 
       if (g_q.pop(&i)) 
         std::cout << i << std::endl; 
       //else 
         //std::cout << "can not pop" << std::endl; 
       usleep(::rand()%1000); 
     } 
     return 0; 
} 


int main(int argc, char* argv[]) 
{ 
     pthread_t t1,t2; 
     pthread_create(&t1, 0, thread1, 0); 
     pthread_create(&t2, 0, thread2, 0); 
     char ch; 
     while (1) 
     { 
       std::cin >> ch; 
       if (ch == 'q') 
         break; 
     } 
     return 0; 
} 
+0

http://isvolatileusefulwiththreads.com/を参照してください。 –

答えて

2

volatile限定状況で動作しますが、あなたがそれを使用しているない方法することができます。


また、バグや2を持って、初期化時にダミーノードを割り当てることは物事を複雑にしました:

bool 
push(QElmType e) 
{ 
    struct qnode <QElmType> *p = new qnode <QElmType>; 

    if (!p) 
     return false; 

    p->next = 0; 

    // BUG: _not_ thread safe because multiple things being updated 
    m_rear->next = p; 

    // BUG: you want to set p->data here 
    m_rear->data = e; 

    m_rear = p; 

    return true; 
} 

bool 
pop(QElmType *e) 
{ 

    if (m_front == m_rear) 
     return false; 

    struct qnode <QElmType> *p = m_front; 

    *e = p->data; 
    m_front = p->next; 
    delete p; 

    return true; 
} 

ここでロックを使用してクリーンアップコードがあります。 注:「リングキュー」実装をしようとしていたのであれば、それを非円形リストに単純化しました。私はロックについてもっと心配していました。でも、元のバージョンと、ロックがまだvolatileの簡単な有効の使用は次のようになり

bool 
init() 
{ 

    m_front = m_rear = nullptr; 

    return true; 
} 

bool 
push(QElmType e) 
{ 
    struct qnode <QElmType> *p = new qnode <QElmType>; 

    if (! p) 
     return false; 

    p->next = 0; 
    p->data = e; 

    // with the lock, now the _multiple_ can be updated _atomically_ 
    lock(); 

    if (m_front == nullptr) 
     m_front = p; 

    if (m_rear != nullptr) 
     m_rear->next = p; 

    m_rear = p; 

    unlock(); 

    return true; 
} 

bool 
pop(QElmType *e) 
{ 
    bool valid; 

    lock(); 

    struct qnode <QElmType> *p = m_front; 

    valid = (p != nullptr); 

    if (valid) { 
     *e = p->data; 

     m_front = p->next; 
     if (p == m_rear) 
      m_rear = m_front; 

     delete p; 
    } 

    unlock(); 

    return valid; 
} 

が必要とされています

volatile int stopflg; 

void * 
thread1(void *l) 
{ 
    while (! stopflg) { 
     // ... 
    } 

    return 0; 
} 

void * 
thread2(void *l) 
{ 
    while (! stopflg) { 
     //... 
    } 

    return 0; 
} 

int 
main(int argc, char *argv[]) 
{ 
    pthread_t t1, 
    t2; 

    pthread_create(&t1, 0, thread1, 0); 
    pthread_create(&t2, 0, thread2, 0); 

    char ch; 

    while (1) { 
     std::cin >> ch; 
     if (ch == 'q') { 
      stopflg = 1; 
      break; 
     } 
    } 

    return 0; 
} 
4

volatileは、マルチスレッドの安全性を保証するものではありません。

ノートのタイトル、およびソース注意:

Volatile: Almost Useless for Multi-Threaded Programming

をvolatileキーワードが マルチスレッドプログラミングのために良好であることを広範な概念があります。私は揮発性のある 修飾子が「マルチスレッド プログラミングのために使用されるかもしれない」と正当化されたインタフェースを見てきました。私は最後の数週間、それは が最終的に私に(またはあなたが好きな場合は、私の太い頭を持って)得たと考えていた マルチスレッドプログラミングのためにほとんど役に立たないです。 ここでは、マルチスレッドの コードからそのほとんどをスクラブする必要がある理由を説明します。

...

-1

揮発性変数はいつでも変更できることを示す、コンパイラ・ディレクティブです。コンパイラが最適化を実行してエラーが発生するのを防ぐためです。メモリマップされたハードウェアのCコードを書くときに便利です - デバイスのI/Oは変数の状態を変更することができます。

これは、マルチスレッドコードを書くこととはまったく関係がありません。

Why is volatile needed in C?

+0

'volatile'はコンパイラ指令ではありません。それはコア言語の一部です。 –

+0

はい、それは次のとおりです。 「https://www.arduino.cc/en/Reference/Volatile」 私はそれがあった言わなかった 注意「変数は揮発性宣言すると、コンパイラへのディレクティブです」プリプロセッサディレクティブ。 –

関連する問題