首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在c++11中后台运行线程

在c++11中后台运行线程
EN

Stack Overflow用户
提问于 2015-05-12 23:15:15
回答 2查看 11.2K关注 0票数 3

我有一个带有connect_to方法的类,我在里面启动了一个线程,在调用它并加入它之后,我希望线程在后台运行,程序执行将继续,但它在我的connect_to方法中挂起,直到线程执行停止。我记得我曾经在C#中使用线程,一旦我启动它们,它们就会在后台运行。

代码语言:javascript
复制
#ifndef _TCP_CLIENT_H_
#define _TCP_CLIENT_H_

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

void connection_thread(void *user);


class TCPClient
{

public:
    SOCKET                m_ConnectSocket = INVALID_SOCKET;
    char                  m_recvbuf[BUFFER_LENGTH];
    int                   m_recvbuflen = BUFFER_LENGTH;
    struct addrinfo*      m_result = NULL, *m_ptr = NULL, m_hints;
    vector<PacketInfo*>   m_packet_list;
    PacketInfo*           m_packet_data = new PacketInfo();
    thread*               m_conn_thread;

    int state = 0;
    char* ip_address;
    unsigned int port = 0;

    TCPClient() {}
    ~TCPClient() {
        delete m_packet_data;
    }


    int Init_Sockets() {
        WSADATA wsaData;
        int iResult;

        iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
        if (iResult != 0) {
            printf("WSAStartup failed with error: %d\n", iResult);
            return 0;
        }
        return 1;
    }



    int Connect_to(char* ip, unsigned int port_number) {
        port = port_number;
        ip_address = ip;

        //thread conn_thread(connection_thread, this);
                thread conn_thread([=]() {connection_thread(this); return 1; });
        conn_thread.join();



        state = 0;
        return 1;
    }


}; // end TCPClient class




void connection_thread(void *user) {
    TCPClient * self = static_cast<TCPClient*>(user);


        // connecting code here... //


    self->state = CONNECTED;
    do {

        iResult = recv(self->m_ConnectSocket, self->m_recvbuf, self->m_recvbuflen, 0);
        if (iResult > 0) {
            printf("Bytes received: %d\n", iResult);
        }
        else if (iResult == 0) {
            printf("Connection closed\n");
            self->state = DISCONNECTED;
        }
        else {
            //printf("recv failed with error: %d\n", WSAGetLastError());
        }

    }
    while (iResult > 0);
}

#endif

线程按预期工作,并持续循环,直到连接关闭。知道我错过了什么吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-05-15 17:47:21

它挂起是因为对join()的调用导致当前线程暂停,直到加入线程完成,此时对join()的调用将返回。

代码语言:javascript
复制
 conn_thread.join();   // Current thread will wait
                       // until conn_thread finishes.

您还在注释中提到,如果不执行连接,则会得到一个名为的中止。这是因为如果线程的析构函数表示的线程仍然是joinble,则它调用terminate()

因为线程对象是本地的,所以它会在调用Connect_to()的末尾被销毁。

代码语言:javascript
复制
int Connect_to(char* ip, unsigned int port_number) {

    // Here you have defined a variable local to the function
    // Thus its constructor is called here (which starts the thread)
    thread conn_thread([=]() {connection_thread(this); return 1; });


    // conn_thread.join();
}
    // The destructor is called here.
    // If the thread is still running at this point you will
    // get a call to `terminate()`

那么如何才能阻止这种情况。

  1. 您可以调用detach()方法。
  2. 您可以使thread属于更大的上下文,这样它就不会被销毁。

调用detach()不是一个好主意。当你松开所有对正在运行的线程的引用,与它的通信变得很困难。

我还注意到您的class TCPClient中有一个成员

代码语言:javascript
复制
thread*               m_conn_thread;

这似乎没有被使用。

如果你在这个对象中存储线程,它将和对象一样长(因此比函数长)。很明显,由于线程访问对象的成员,所以对象应该和线程一样持续时间。

因此,我将进行以下更改:

代码语言:javascript
复制
 // 1 Make the member a real variable not a pointer.
 std::thread               m_conn_thread;

 // 2 Initialize this in the constructor.
 TCPClient()
    : m_conn_thread()   // no thread created with this constructor.
 {}

 // 3 Create and assing a thread to this variable.
 int Connect_to(char* ip, unsigned int port_number) {
      // STUFF
      m_conn_thread = std::move(std::thread([=]() {connection_thread(this); return 1; }));
      // MORE STUFF
  }

  // Add a destructor that waits for the thread to join.
  ~TCPClient()
  {
      // As the thread is using members from this object
      // We can not let this obect be destroyed until
      // the thread finishes executing.
      m_conn_thread.join();

      // At this point the thread has finished.
      // Destructor can now complete.



       // Note: Without the join.
       //       This could potentially call terminate()
       //       as destroying the member m_conn_thread while the
       //       the thread is still running is bad.
  }
票数 2
EN

Stack Overflow用户

发布于 2015-05-12 23:17:18

我有一个带有connect_to方法的类,我在其中启动了一个线程,在调用它并加入它之后,我希望线程在后台运行,程序执行将继续,但它挂在我的connect_to方法中,直到线程执行停止

这就是加入一个线程应该做的事情!

如果你不想加入这个线程,那就干脆不要。:)

不过,您可能至少应该在类析构函数中或在以后的某个时间执行此操作,这样当辅助线程仍在执行时,您的主线程就不会尝试结束。因为那会以泪水收场。

在我看来,这是一个完美的例子,说明了为什么我们不应该在不理解为什么要这样做的情况下编写代码行。:)您已经对conn_thread.join()的含义做了一个假设,这个假设是错误的:在这种情况下,首先要做的事情之一是阅读文档,以确保您的假设成立。理想情况下,您应该在编写代码之前阅读它,但没关系。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30195015

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档