2

我有一个程序可以处理在本地网络上以 UDP 数据包广播的神经尖峰数据。

我当前的程序有两个线程,一个 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

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

4

4 回答 4

3

我要在这里勉强说你所有的问题都是由spike_net_t数组的归零引起的。

在 C++ 中,您不能将具有非[insert word for 'struct-like' here]成员的对象清零。即,如果您有一个包含复杂对象(std 字符串、向量等)的对象,则不能将其归零,因为这会破坏在构造函数中完成的对象的初始化。

于 2011-09-29T22:37:22.617 回答
1

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

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

在尝试调用其 getNetworkSpikePacket() 之前,您可以尝试在包装器中声明(sp)吗?

于 2011-09-29T22:26:55.003 回答
0

如果您在spikeBuff任何地方分配数组,请确保您分配了足够的存储空间,因此writeIdx不是越界索引。

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

于 2011-09-29T20:55:04.153 回答
0

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

SpikePlot 和 TetrodePlot 是否相关?您发布的内容中没有提到这一点。

于 2011-09-29T21:09:40.207 回答