2017-06-24 15 views
1

参照渡し後にclient.cpp内のdata_receivedベクターをクリアするとき、未定義の振る舞いを扱っていたのか不思議です。私は無効なデータで問題が発生したことはありませんしかし、これはどこに問題があるかもしれないか分かります潜んでいます。 vectorは最後のキューに参照渡しされています。一方、もう1つのスレッドはqueue_event.notify_all()が起動した後にのみ独自のレートでデキューされます。参照でベクターを渡してから呼び出しをクリアする

この問題が発生した場合は、のクライアントのの受信をブロックした直後に解決策が明らかになっていると思います。思考?

blocking_queue.h

template <typename T> 
class BlockingQueue { 
    ... 
    std::queue<T> queue; 
    ... 
}; 

blocking_queue.cpp

template <class T> 
void BlockingQueue<T>::enqueue(T const &item) 
{ 
    std::unique_lock<std::mutex> lk (queue_lock); 
    queue.push(item); 
    lk.unlock(); 
    queue_event.notify_all(); 
} 

template <class T> 
T BlockingQueue<T>::dequeue() 
{ 
    std::unique_lock<std::mutex> lk (queue_lock); 
    if(queue_event.wait_for(lk, std::chrono::milliseconds(dequeue_timeout)) == std::cv_status::no_timeout) 
    { 
     T rval = queue.front(); 
     queue.pop(); 
     return rval; 
    } 
    else 
    { 
     throw std::runtime_error("dequeue timeout"); 
    } 
} 

client.cpp

void Client::read_from_server() 
{ 
    std::vector<uint8_t> data_received; 

    while(run) 
    { 
     if (client->is_connected()) 
     { 
      uint8_t buf[MAX_SERVER_BUFFER_SIZE]; 
      int returned; 

      memset(buf, 0, MAX_SERVER_BUFFER_SIZE); 
      returned = client->receive(client->get_socket_descriptor(), buf, MAX_SERVER_BUFFER_SIZE); 
      // should probably move data_received.clear() to here!! 
      if (returned > 0) 
      { 
       for (int i = 0; i < returned; i++) 
       { 
        data_received.push_back(buf[i]); 
       } 

       if (incoming_queue) 
       { 
        incoming_queue->enqueue(data_received); 
       } 

       data_received.clear(); 
      } 
      else 
      { 
       client->set_connected(false); 
      } 
     }  
    } 
} 

答えて

1

私は表示されません​​のために潜在的なUBが発生する可能性があります。これは、incoming_queue->enqueue(data_received);が呼び出されたときに、std::queue<T> queue;には渡されたアイテム(ベクトル)のコピーが保持されるためです。

キューへのアクセスがよく同期されている場合は、そのコードは安全でなければなりません。

+0

ahhhは、voidのstd :: queue push(const value_type & val);? – atomSmasher

+2

@atomSmasher)のためのものです。実際には 'const'についてはそうではありません。値のコピーとして初期化される](http://en.cppreference.com/w/cpp/container/list/push_back)(値が一時的であるか、コンパイラが値の状態があなたのケースでは 'T'は'ベクトル 'なのでコピーまたは移動されますが、後でそれをクリアすることは問題ありません。実際に' container 'は' T 'が渡されたTのコピーや移動を行います。' T'がポインタ型のときは心配する必要があります。 –

+0

wow。正しいです。 – atomSmasher

関連する問題