2017-07-11 1 views
0

Ich versuche, Boost-Kanäle und Fasern in einer Klasse zu verwenden. Hier ist ein einfacher Testfall der funktioniert aber es ist nicht genau das, was ich will. Wenn ich "line: 1" nach "loc: 1" verschiebe, hängt das Programm (gdb zeigt an einem Spinlock in boost :: fibles nach c-> push (a)). Kann mir jemand helfen, indem er zeigt, was ich falsch mache? Vielen Dank. HierWie Boost-Kanäle (und Fasern) richtig in einer Klasse zu verwenden?

ist der Beispielcode, der arbeitet und produziert die folgenden

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

Ausgang:

do_work 
_send 
Sending: 1000 
_recv 
Received: 1000 

Zusammengestellt mit:

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 

Antwort

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

in Block() wird arbeiten nicht weil Temp den Gültigkeitsbereich verlässt nach Block() ‚s Körper und _chan verlassen zu Müll/befreit Speicher zeigen würde

zwei Varianten sind möglich:

1) Behalte den Kanal temp eine lokale Variable von 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) halten Kanal Temp eine Membervariable von Block <>:

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(); 
    } 
}; 

beide Versionen erzeugen:

do_work 
_send 
Sending: 1000 
_recv 
Received: 1000 
1

Wenn Sie das Konstrukt Kanal ein der Block-Konstruktor und nehmen Sie einen Zeiger darauf, zeigt der Zeiger _chan auf Müll, wenn temp außerhalb des Geltungsbereichs geht. Du könntest einfach temp ein Mitglied von Block machen oder es dort lassen wo es so weiter geht.

Update: Brackets (Klammern) in C++ definiert Umfang

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 

Dann eine Speicher Uhr verwenden, um _chan zu suchen. Wenn Sie sich an der schließenden Klammer vorbeibewegen, sollten Sie sehen, dass der Speicher zu Müll wird, wenn Temp zerstört wird. Wenn Sie an diesem Punkt nachverfolgen, werden Sie sehen, dass temp ihren Distributor trifft.

Ich würde nur die temp in do_work verlassen.

+0

Es schien einen gültigen User-Space-Zeiger zu haben, aber ich bin mir nicht 100% ig sicher. Ich werde es heute Abend versuchen und hier antworten. Vielen Dank. – coder23

+0

Nein, es hat das Verhalten außer gelegentlichen segfaults nicht geändert. :( – coder23

0

Ok, erklärt channel_t als Mitglied gut funktioniert. Ich denke, es deutet auf Müll hin. Außerdem habe ich gelernt, dass Boost-Sync-Primitive nicht gerne std :: move (ed) sind.

Danke Jungs für die Hilfe.

Verwandte Themen