【问题标题】:std::list crashes in libev callbackstd::list 在 libev 回调中崩溃
【发布时间】:2012-06-22 21:32:17
【问题描述】:

我有一个 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

【问题讨论】:

    标签: c++ list crash segmentation-fault libev


    【解决方案1】:

    也许您只需要在访问 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()){
     /// ...
    }
    

    在写入此列表时也使用锁。 此外,还可以使用读锁和写锁。写锁总是排他所有其他人(读和写)。并发读取可以同时获取多次读取锁。

    【讨论】:

      【解决方案2】:

      libstdc++ 的std::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 模式下,std::list 中存在一个额外的 size_t 成员,这会改变对象的大小。

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

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

      【讨论】:

      • 感谢您的回答。抱歉,但我是 linux 编程的新手,谷歌搜索并没有给我一个关于如何更改库的答案。我应该改用 4.7 吗?
      • 不,这无济于事。你需要使用c++11模式重新编译libev,或者你的程序中不要使用C++11
      • 使用 -std=c++0x 重建 libev,但具有相同的程序行为..(仅使用 libev 和 pthread 库)再等一下 - 在其他程序部分 std::list 没有t 崩溃
      • Nitpick:我怀疑新的size_t 成员仅存在于 C++11 模式中。 C++11 需要进行这种更改,但它也将用于 C++98 模式。因此,这是 libstdc++ 版本之间的二进制不兼容,而不是 C++98 和 C++11 模式之间的二进制不兼容。
      • @MarcMutz,不,检查来源或上面的链接。对于 c++98,libstdc++ abi 多年来没有改变。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-05-14
      • 1970-01-01
      • 2021-10-04
      • 1970-01-01
      • 2021-06-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多