开发者

Trouble tracking down a Bus Error/Seg Fault in C++ and Linux

开发者 https://www.devze.com 2023-04-10 02:45 出处:网络
I have a program that processes neural spike data that is broadcast in UDP packets on a local network.

I have a program that processes neural spike data that is broadcast in UDP packets on a local network.

My current program has two threads a UI thread and a worker thread. The worker thread simply listens for data packets, parses them and makes them available to the UI thread for display and processing. My current implementation works just fine. However for a variety of reasons I'm trying to re-write the program in C++ using an Object Oriented approach.

The current working program initialized the 2nd thread with:

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

Here is the getNetSpike function that is called by the new thread:

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

Now in my new OO version of the program I setup the 2nd thread in much the same way:

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

However, because pthead_create takes a pointer to a void function and not a pointer to an object's member method I needed to create this simple function that wraps the SpikePlot.getNetworSpikePacket() method

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

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

Which then calls the getNetworkSpikePacket() method:

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++; 
}

The code for the two implementations is nearly identical but the 2nd implementation (OO version) crashes with a SegFault or BusError after the first packet that is read. Using printf I've narrowed down which line is causing the error:

spikeBuff[writeIdx] = s;

and for the life of me I can't figure out why its causing my program to crash.

What am I doing wrong here?

Update: I define spikeBuff as a private member of the class:

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

Then in the SpikePlot constructor I call:

bzero(&spikeBuff, sizeof(spikeBuff));

and set:

writeIdx =0;

Update 2: Ok something really weird is going on with my index variables. To test their sanity I changed getNetworkSpikePacket to:

vo开发者_JAVA百科id 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);
}

And I get the following output to the console:

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

This method is the only method where I update their values (besides the constructor where I set them to 0). All other uses of these variables are read only.


I'm going to go on a limb here and say all your problems are caused by the zeroing out of the spike_net_t array.

In C++ you must not zero out objects with non-[insert word for 'struct-like' here] members. i.e. if you have an object that contains a complex object (a std string, a vector, etc. etc.) you cannot zero it out, as this destroys the initialization of the object done in the constructor.


This may be wrong but....

You seemed to move the wait loop logic out of the method and into the static wrapper. With nothing holding the worker thread open, perhaps that thread terminates after the first time you wait for a UDP packet, so second time around, sp in the static method now points to an instance that has left scope and been destructed?

Can you try to assert(sp) in the wrapper before trying to call its getNetworkSpikePacket()?


It looks like your reinterpret_cast might be causing some problems. When you call pthread_create, you are passing in "this" which is a SpikePlot*, but inside networkThreadFunc, you are casting it to a TetrodePlot*.

Are SpikePlot and TetrodePlot related? This isn't called out in what you've posted.


If you are allocating the spikeBuff array anywhere then make sure you are allocating sufficient storage so writeIdx is not an out-of-bounds index.

I'd also check that initNetworkRxThread is being called on an allocated instance of spikePlot object (and not on just a declared pointer).

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号