2

ローカル ネットワーク上の UDP パケットでブロードキャストされる神経スパイク データを処理するプログラムがあります。

私の現在のプログラムには、UI スレッドとワーカー スレッドの 2 つのスレッドがあります。ワーカー スレッドは単にデータ パケットをリッスンして解析し、UI スレッドで表示および処理できるようにします。私の現在の実装は問題なく動作します。しかし、さまざまな理由から、オブジェクト指向アプローチを使用して C++ でプログラムを書き直そうとしています。

現在の作業プログラムは、2 番目のスレッドを次のように初期化しました。

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 バージョンでは、ほぼ同じ方法で 2 番目のスレッドをセットアップします。

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

2 つの実装のコードはほぼ同じですが、2 番目の実装 (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++ では、 [ここに「構造体のような」単語を挿入]以外のメンバーを持つオブジェクトをゼロに設定してはなりません。つまり、複雑なオブジェクト (std 文字列、ベクトルなど) を含むオブジェクトがある場合、コンストラクターで行われたオブジェクトの初期化が破棄されるため、それをゼロにすることはできません。

于 2011-09-29T22:37:22.617 に答える
1

これは間違っているかもしれませんが....

待機ループ ロジックをメソッドから静的ラッパーに移動したようです。ワーカー スレッドを開いたままにしておくものが何もない場合、UDP パケットを最初に待機した後にそのスレッドが終了する可能性があります。そのため、2 回目は、静的メソッドの sp がスコープを離れて破棄されたインスタンスを指すようになりますか?

getNetworkSpikePacket() を呼び出す前に、ラッパーで assert(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 に答える