无法跟踪C ++和Linux中的总线错误/段错误

时间:2011-09-29 20:45:57

标签: c++ linux pthreads segmentation-fault bus-error

我有一个程序来处理在本地网络上以UDP数据包广播的neural spike data

我当前的程序有两个线程,一个UI线程和一个工作线程。工作线程只是监听数据包,解析它们并使它们可供UI线程使用以进行显示和处理。我当前的实现工作正常。但是由于各种原因,我试图使用面向对象的方法在C ++中重新编写程序。

当前工作程序使用以下命令初始化第二个线程:

pthread_t netThread;
net = NetCom::initUdpRx(host,port);
pthread_create(&netThread, NULL, getNetSpike, (void *)NULL);

以下是新线程调用的getNetSpike函数:

void *getNetSpike(void *ptr){
    while(true)
    {
        spike_net_t s;
        NetCom::rxSpike(net, &s);
        spikeBuff[writeIdx] = s;
        writeIdx = incrementIdx(writeIdx);
        nSpikes+=1;
        totalSpikesRead++;
    }
} 

现在在我的程序的新OO版本中,我以相同的方式设置第二个线程:

void SpikePlot::initNetworkRxThread(){
    pthread_t netThread;
    net = NetCom::initUdpRx(host,port);
    pthread_create(&netThread, NULL, networkThreadFunc, this);
}

但是,因为pthead_create采用指向void函数的指针而不是指向对象成员方法的指针,我需要创建这个包含SpikePlot.getNetworSpikePacket()方法的简单函数

void *networkThreadFunc(void *ptr){
        SpikePlot *sp = reinterpret_cast<SpikePlot *>(ptr);

    while(true)
    {
        sp->getNetworkSpikePacket();
    }
}

然后调用getNetworkSpikePacket()方法:

void SpikePlot::getNetworkSpikePacket(){

    spike_net_t s;
    NetCom::rxSpike(net, &s);
    spikeBuff[writeIdx] = s;  // <--- SegFault/BusError occurs on this line
    writeIdx = incrementIdx(writeIdx);
    nSpikes+=1;
    totalSpikesRead++; 
}

这两个实现的代码几乎完全相同,但第二个实现(OO版本)在读取的第一个数据包之后与SegFault或BusError崩溃。使用printf我缩小了导致错误的行:

spikeBuff[writeIdx] = s;

对于我的生活,我无法弄清楚为什么它导致我的程序崩溃。

我在这里做错了什么?

更新: 我将spikeBuff定义为该类的私有成员:

class SpikePlot{
private:
    static int const MAX_SPIKE_BUFF_SIZE = 50;
    spike_net_t spikeBuff[MAX_SPIKE_BUFF_SIZE];
       ....
}

然后在SpikePlot构造函数中我调用:

bzero(&spikeBuff, sizeof(spikeBuff));

并设置:

writeIdx =0;

更新2 :好吧我的索引变量真的很奇怪。为了测试他们的理智,我将getNetworkSpikePacket更改为:

void TetrodePlot::getNetworkSpikePacket(){
    printf("Before:writeIdx:%d nspikes:%d totSpike:%d\n", writeIdx, nSpikes, totalSpikesRead);

    spike_net_t s;
    NetCom::rxSpike(net, &s);
//  spikeBuff[writeIdx] = s;
    writeIdx++;// = incrementIdx(writeIdx);
//  if (writeIdx>=MAX_SPIKE_BUFF_SIZE)
        // writeIdx = 0;
    nSpikes += 1;
    totalSpikesRead += 1; 
    printf("After:writeIdx:%d nspikes:%d totSpike:%d\n\n", writeIdx, nSpikes, totalSpikesRead);
}

我得到以下输出到控制台:

Before:writeIdx:0 nspikes:0 totSpike:0
After:writeIdx:1 nspikes:32763 totSpike:2053729378

Before:writeIdx:1 nspikes:32763 totSpike:2053729378
After:writeIdx:1 nspikes:0 totSpike:1

Before:writeIdx:1 nspikes:0 totSpike:1
After:writeIdx:32768 nspikes:32768 totSpike:260289889

Before:writeIdx:32768 nspikes:32768 totSpike:260289889
After:writeIdx:32768 nspikes:32768 totSpike:260289890

此方法是 only 方法,我更新它们的值(除了我将它们设置为0的构造函数)。这些变量的所有其他用法都是只读的。

4 个答案:

答案 0 :(得分:3)

我将在这里继续讨论,并说你所有的问题都是由spike_net_t数组的清零引起的。

在C ++中,你不得将非 [插入类似'struct-like'此处] 成员的对象归零。即如果你有一个包含复杂对象的对象(std字符串,向量等等),你就不能把它归零,因为这会破坏构造函数中对象的初始化。

答案 1 :(得分:1)

这可能是错的,但......

您似乎将等待循环逻辑移出方法并进入静态包装器。没有任何东西保持工作线程打开,也许该线程在第一次等待UDP数据包后终止,所以第二次,静态方法中的sp现在指向一个已经离开范围并被破坏的实例?

在尝试调用getNetworkSpikePacket()之前,你可以尝试在包装器中断言(sp)吗?

答案 2 :(得分:0)

如果要在任何地方分配spikeBuff数组,请确保分配足够的存储空间,以使writeIdx不是超出范围的索引。

我还要检查在initNetworkRxThread对象的已分配实例上调用spikePlot(而不仅仅是在声明的指针上)。

答案 3 :(得分:0)

看起来你的reinterpret_cast可能会导致一些问题。当你调用pthread_create时,你传入的是“this”这是一个SpikePlot *,但在networkThreadFunc中,你将它转换为TetrodePlot *。

SpikePlot和TetrodePlot是否相关?你发布的内容没有提及。