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

在第二种情况下,empty() 返回 false,但调试器显示,该列表没有数据成员

它在单独的线程中运行(缓冲区是从同一个线程读取和写入的)我还尝试将其移动到主线程而不启动任何其他线程,但效果相同。

操作系统是 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++'sstd::list在 c++98 和 c++11/c++0x 模式之间不兼容。见http://gcc.gnu.org/wiki/Cxx11AbiCompatibility

原因是在 c++98 中它不需要为std::list::size()O(1),而 libstdc++ 将其实现为 O(n)。在 C++11 中,它必须为 O(1),因此在 C++11 模式size_t中存在一个额外的成员std::list,这会改变对象的大小。

如果您的应用程序使用 C++11,那么通常您链接到的所有库也应该这样做。

编辑:抱歉,我刚刚意识到你说的是 GCC 4.6,它还没有std::list::size()改变,所以你的问题一定是别的。

于 2012-06-22T21:45:08.737 回答