1

クライアントに送信される保留中のデータをチェックする libev 書き込みコールバック関数があります。保留中のデータ バッファーは次のようになります。

struct PendingData{
  unsigned short data_size;
  char data[4096];
};
typedef std::list<PendingData*> PendingBuf;

class Client{
private:
  int sock;
  PendingBuf data_list;
public:
  ev::io cl_io;
  void write_cb(ev::io &watcher, int events);
};

コールバック関数は、次の方法でコンテナーにデータがあるかどうかを確認します。

void Client::write_cb(ev::io &watcher, int events){
  PendingData* pd = NULL;
  int ires = 0;
  if(!data_list.empty()){
    pd = data_list.front();
    ires = send(sock, pd->data, pd->data_size, 0);
    if(ires == pd->data_size){
      delete pd;
      data_list.pop_front();
      return;
    }
    // .... additional checking here 
  }
} 

セグメンテーション違反でプログラムがクラッシュする

if(!data_list.empty())

そして時々

pd = data_list.front();

2 番目のケースでは、empty() は false を返しますが、デバッガーは、そのリストにはデータ メンバーがありません

別のスレッドで実行されます(バッファは同じスレッドから読み書きされます)追加のスレッドをまったく開始せずにこれをメインスレッドに移動しようとしましたが、同じ効果がありました。

OS は Ubuntu 12.04、コンパイラは g++ 4.6 です。私のプロジェクトでは c++0x も有効になっています。

4

2 に答える 2

2

たぶん、std :: listのようなアクセス中にロック(ミューテックス)を使用する必要があるだけです

// near list
class Client {
 /// ...
    PendingBuf data_list;
    std::mutex list_lock;
 /// ...
}

void Client::write_cb(ev::io &watcher, int events){
   std::lock_guard<std::mutex> lock(list_lock);
   if(!data_list.empty()){
 /// ...
}

このリストに書き込むときは、ロックも使用します。また、読み取りロックと書き込みロックを使用する可能性があります。書き込みロックは常に他のすべてを排他的にします(読み取りと書き込み)。同時読み取りの場合、読み取りロックを同時に何度も取得できます。

于 2012-09-11T16:01:33.040 に答える
0

libstdc++std::listは、c++98 と c++11/c++0x モードの間で互換性がありません。http://gcc.gnu.org/wiki/Cxx11AbiCompatibilityを参照

その理由は、c++98 では O(1) である必要がなくstd::list::size()、libstdc++ が O(n) として実装したためです。C++11 では O(1) である必要があるため、追加のsize_tメンバーがstd::listC++11 モードに存在し、オブジェクトのサイズが変更されます。

アプリケーションが C++11 を使用している場合、通常、リンク先のすべてのライブラリも C++11 を使用する必要があります。

編集: 申し訳ありませんが、まだ変更がない GCC 4.6 と言っていたことに気付きましたstd::list::size()。そのため、問題は別のものに違いありません。

于 2012-06-22T21:45:08.737 に答える