2013-03-07 125 views
1

我正尝试使用C++ 11中的线程库编写多线程软件。在互联网上发现的一些基本教程可以按预期进行编译和运行。但是我自己的应用程序分为类,总是抛出异常。如何避免在C++ 11中出现<thread>引发的异常?

任何人都可以告诉我应该修复哪部分代码吗?

$ clang++ -std=c++11 -stdlib=libc++ BaseInterface.cxx -c -o BaseInterface.o 
$ clang++ -std=c++11 -stdlib=libc++ SocketReceiver.cxx -c -o SocketReceiver.o 
$ clang++ -std=c++11 -stdlib=libc++ main.cxx -c -o main.o 
$ clang++ -std=c++11 -stdlib=libc++ main.o BaseInterface.o SocketReceiver.o -o main 
$ gdb main 
(gdb) run 
Starting program: /Users/oxon/test/main 
Reading symbols for shared libraries ++............................ done 
libc++abi.dylib: terminate called throwing an exception 

Program received signal SIGABRT, Aborted. 
[Switching to process 859 thread 0x40b] 
0x00007fff88df8212 in __pthread_kill() 
(gdb) bt 
#0 0x00007fff88df8212 in __pthread_kill() 
#1 0x00007fff8bc85af4 in pthread_kill() 
#2 0x00007fff8bcc9dce in abort() 
#3 0x00007fff894d3a17 in abort_message() 
#4 0x00007fff894d13c6 in default_terminate() 
#5 0x00007fff89874887 in _objc_terminate() 
#6 0x00007fff894d13f5 in safe_handler_caller() 
#7 0x00007fff894d1450 in std::terminate() 
#8 0x00007fff894d25b7 in __cxa_throw() 
#9 0x00007fff8a9ba3b9 in std::__1::thread::join() 
#10 0x0000000100000cf0 in SocketReceiver::Receive() 
#11 0x0000000100000c6d in SocketReceiver::DoReceive() 
#12 0x0000000100001593 in _ZNSt3__114__thread_proxyINS_5tupleIJPFPvS2_ES2_EEEEES2_S2_() 
#13 0x00007fff8bc84742 in _pthread_start() 
#14 0x00007fff8bc71181 in thread_start() 

这是OS X 10.8上的结果。使用GCC 4.4的科学Linux 6也提供了类似的结果。

= BaseInterface.h =

#ifndef BASE_INTERFACE_H 
#define BASE_INTERFACE_H 

#include "SocketReceiver.h" 

class BaseInterface 
{ 
private: 
    SocketReceiver* fReceiver; 

public: 
    BaseInterface(); 
    virtual ~BaseInterface(); 

    virtual void Close(); 
    virtual void Open(); 
; 

#endif 

= BaseInterface.cxx =

#include <iostream> 

#include <string.h> 
#include <unistd.h> 

#include "BaseInterface.h" 

BaseInterface::BaseInterface() 
{ 
    fReceiver = new SocketReceiver(this); 
} 

//______________________________________________________________________________ 
BaseInterface::~BaseInterface() 
{ 
    Close(); 
    delete fReceiver; 
    fReceiver = 0; 
} 

//______________________________________________________________________________ 
void BaseInterface::Close() 
{ 
    fReceiver->Stop(); 
    usleep(10000); 

    while(fReceiver->IsRunning()){ 
    usleep(10000); 
    } // while 
} 

//______________________________________________________________________________ 
void BaseInterface::Open() 
{ 
    fReceiver->Start(); 

} 

= SocketReceiver.h =

#ifndef SOCKET_RECEIVER_H 
#define SOCKET_RECEIVER_H 

#include <thread> 
#include <mutex> 

class BaseInterface; 

class SocketReceiver 
{ 
private: 
    BaseInterface*    fInterface; 
    bool      fIsRunning; 
    std::mutex     fMutex; 
    bool      fStop; 
    std::thread*    fThread; 

public: 
    SocketReceiver(BaseInterface* interface = 0); 
    virtual ~SocketReceiver(); 

    bool    IsRunning() const {return fThread ? true : false;} 
    static void*  DoReceive(void* arg); 
    void    Receive(); 
    void    Start(); 
    void    Stop(); 
}; 

#endif 

= SocketReceiver.cxx =

#include <iostream> 
#include <thread> 
#include <unistd.h> 

#include "BaseInterface.h" 
#include "SocketReceiver.h" 

SocketReceiver::SocketReceiver(BaseInterface* interface) 
{ 
    fInterface = interface; 
    fStop = true; 
    fThread = 0; 
} 

//______________________________________________________________________________ 
SocketReceiver::~SocketReceiver() 
{ 
} 

//______________________________________________________________________________ 
void* SocketReceiver::DoReceive(void* arg) 
{ 
    SocketReceiver* receiver = (SocketReceiver*)arg; 
    receiver->Receive(); 

    return 0; 
} 

//______________________________________________________________________________ 
void SocketReceiver::Receive() 
{ 
    while(not fStop){ 
    fMutex.lock(); 
    usleep(10000); 
    fMutex.unlock(); 
    } // while 

    fThread->join(); 

    delete fThread; 
    fThread = 0; 
} 

//______________________________________________________________________________ 
void SocketReceiver::Start() 
{ 
    fStop = false; 
    fThread = new std::thread(DoReceive, (void*)this); 
} 

//______________________________________________________________________________ 
void SocketReceiver::Stop() 
{ 
    fStop = true; 
} 

= main.cxx =

#include "BaseInterface.h" 

int main() 
{ 
    BaseInterface interface; 
    interface.Open(); 
    interface.Close(); 

    return 0; 
} 

回答

4

你本身加入线程。在线程中调用join,如在SocketReceiver::Stop中。

当调用join时,它清除底层数据。如果你在运行的线程中调用它,那么当线程仍然需要时,这些数据将被删除。

4

如果由std::thread运行的函数通过和异常退出,则将调用std::terminate

std::thread::join()指定抛出std::system_error错误代码resource_deadlock_would_occur如果join()被称为在同一个线程,即线程不能加入本身。所以你试图让线程自己加入会导致异常终止进程。一个线程无法自己加入,连接被定义为“等待线程完成”,显然不能由线程本身完成,它会阻止等待自己完成,直到join()的调用完成时才会发生,这将不会发生直到线程完成后才能发生,直到join()的调用完成后才能发生......您能看到这种情况吗?

此外,你为什么这样做?

fThread = new std::thread(DoReceive, (void*)this); 

std::threadpthread_create,你不需要通过它void*,刚刚摆脱DoReceive,并呼吁:

fThread = new std::thread(&SocketReceiver::Receive, this); 

为什么是你的std::threadnew分配呢?这也不是必需的,您可以使用std::thread成员并使用joinable()来检查它是否处于活动状态,而不是检查指针是否为非空值。

+0

感谢您的详细评论。我还在寻找不需要DoReceive和空指针检查的标准技术。所以你的建议使我的代码变得理想。 'fThread = new std :: thread(Receive,this);'没有编译。所以我删除了DoReceive(),并将Remove()更改为operator()()根据另一个线程http://stackoverflow.com/questions/9189989/stdthread-start-thread-on-this-from-within-the-类本身 – 2013-03-07 09:59:16

+0

我在一个错误的位置使用join()并准备好DoReceive的原因是,我的软件是使用另一个线程库从旧C++代码更新的。在那个库中,join是在这个错误的位置上工作的,C++ 11像线程构造函数不被支持。 – 2013-03-07 10:08:20