2017-07-11 9 views
0

クラス内でブーストチャンネルとファイバを使用しようとしています。ここでは簡単なテストケースですがうまく動作しますしかし、それは私が欲しいものではありません。 "line:1"を "loc:1"に移動すると、プログラムがハングします(gdbはc-> push(a)の後にboost :: fibres内のスピンロックで表示されます)。私は間違って何を指して誰でも助けてくれる?ありがとう。ここで クラス内でブーストチャンネル(およびファイバー)を正しく使用する方法は?

がある作品と、次を生成し、サンプルコード、

#include <iostream> 
#include <boost/fiber/all.hpp> 

using namespace std; 

template <class T> 
class Block 
{ 
    private: 
     typedef boost::fibers::buffered_channel<T> channel_t; 
     typedef boost::fibers::fiber fiber_t; 
     fiber_t _thread_send; 
     fiber_t _thread_recv; 
     size_t _n; 
     channel_t* _chan; 

    public: 
     Block(size_t n) : _n(n), _chan(nullptr) { 
      // >>>>>>>>>> loc:1 <<<<<<<<<<< 
     } 
     virtual ~Block() {} 
     void _send(channel_t *c) { 
      cout << __func__ << endl; 
      int a = 1000; 
      cout << "Sending: " << a << endl; 
      c->push(a); 
     } 
     void _recv(channel_t *c) { 
      cout << __func__ << endl; 
      int a = 0; 
      c->pop(a); 
      cout << "Received: " << a << endl; 
     } 
     void do_work() { 
      cout << "do_work\n"; 
      channel_t temp{_n}; _chan = &temp; // <<<<<<<<<<<< line:1 
      _thread_send = boost::fibers::fiber(bind(&Block::_send, this, _chan)); 
      _thread_recv = boost::fibers::fiber(bind(&Block::_recv, this, _chan)); 
      _thread_send.join(); 
      _thread_recv.join(); 
     } 
}; 

int main() 
{ 
    Block<int> B(2); 
    B.do_work(); 
    return 0; 
} 

出力:

do_work 
_send 
Sending: 1000 
_recv 
Received: 1000 

を使用してコンパイル:

GNU/Linux 64 bit x86-64 
g++ (GCC) 7.1.1 2017051 
boost 1.64.0 
g++ -c --std=c++14 -g -Wall -Wpedantic boost_channels.cpp -o boost_channels.o 
g++ -lboost_context -lboost_fiber boost_channels.o -o boost_channels 

答えて

1
channel_t temp{_n}; _chan = &temp; // <<<<<<<<<<<< line:1 

2つのバージョンが可能であり、ごみ/解放されたメモリを指しますBlock()の体と_chanを出た後一時がスコープの外に出るので動作しません。 1)チャネルの温度をdo_work()のローカル変数:

template <class T> 
class Block 
{ 
private: 
    typedef boost::fibers::buffered_channel<T> channel_t; 
    typedef boost::fibers::fiber fiber_t; 
    fiber_t _thread_send; 
    fiber_t _thread_recv; 
    size_t _n; 

public: 
    Block(size_t n) : _n(n) { 
    } 
    virtual ~Block() {} 
    void _send(channel_t *c) { 
     cout << __func__ << endl; 
     int a = 1000; 
     cout << "Sending: " << a << endl; 
     c->push(a); 
    } 
    void _recv(channel_t *c) { 
     cout << __func__ << endl; 
     int a = 0; 
     c->pop(a); 
     cout << "Received: " << a << endl; 
    } 
    void do_work() { 
     cout << "do_work\n"; 
     channel_t chan{_n}; 
     _thread_send = boost::fibers::fiber(bind(&Block::_send, this, & chan)); 
     _thread_recv = boost::fibers::fiber(bind(&Block::_recv, this, & chan)); 
     _thread_send.join(); 
     _thread_recv.join(); 
    } 
}; 

2)チャネル一時ブロック<>のメンバー変数保つ:両方のバージョンが生成

template <class T> 
class Block 
{ 
private: 
    typedef boost::fibers::buffered_channel<T> channel_t; 
    typedef boost::fibers::fiber fiber_t; 
    fiber_t _thread_send; 
    fiber_t _thread_recv; 
    channel_t _chan; 

public: 
    Block(size_t n) : _chan(n) { 
    } 
    virtual ~Block() {} 
    void _send(channel_t *c) { 
     cout << __func__ << endl; 
     int a = 1000; 
     cout << "Sending: " << a << endl; 
     c->push(a); 
    } 
    void _recv(channel_t *c) { 
     cout << __func__ << endl; 
     int a = 0; 
     c->pop(a); 
     cout << "Received: " << a << endl; 
    } 
    void do_work() { 
     cout << "do_work\n"; 
     _thread_send = boost::fibers::fiber(bind(&Block::_send, this, & _chan)); 
     _thread_recv = boost::fibers::fiber(bind(&Block::_recv, this, & _chan)); 
     _thread_send.join(); 
     _thread_recv.join(); 
    } 
}; 

を:

do_work 
_send 
Sending: 1000 
_recv 
Received: 1000 
1

あなたが構築のチャンネルtempが範囲外になると、ポインタ_chanはガベージを指し示しています。 tempBlockのメンバーにすることも、それが動作する場所に残して転送することもできます。

更新: ブラケット(括弧)でのC++定義範囲

Block(size_t n) : _n(n), _chan(nullptr) 
    //the scope of the constructor starts at this brace 
{ 
    //temp gets instantiated 
    channel_t temp{_n}; 
    //assign the pointer to the object 
    _chan = &temp; 

} //put a break point here 

はその後_chanを見てメモリウォッチを使用しています。閉じ括弧の前を移動すると、一時的に破壊されてメモリがゴミになっているはずです。その時点でトレースすると、tempがそのディストリビューターに会うのが見えます。

tempdo_workのままにしておきます。

Block()

+0

有効なユーザースペースポインタがあるようですが、100%確実ではありません。私は今夜​​それを試し、ここに返信します。ありがとう。 – coder23

+0

いいえ、時折segfaultsを除いて動作を変更しませんでした。 :( – coder23

0

[OK]を、部材が正常に動作としてchannel_tを宣言する。私はそれがゴミを指していると思います。また、私はブースト同期プリミティブがstd :: move(ed)のように好きではないことを学びました。

ありがとうございました。

関連する問題