在C 11中的背景中运行线程

Running thread in background in c++11

本文关键字:运行 线程 背景      更新时间:2023-10-16

我有一个带有连接方法的类继续,但它挂在我的connect_to方法中,直到线程执行停止。我记得我曾经在C#中使用线程,并且一旦我启动它们,它们就在后台跑了。

#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: %dn", 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: %dn", iResult);
        }
        else if (iResult == 0) {
            printf("Connection closedn");
            self->state = DISCONNECTED;
        }
        else {
            //printf("recv failed with error: %dn", WSAGetLastError());
        }
    }
    while (iResult > 0);
}
#endif

螺纹按预期工作,并保持恒定循环,直到连接关闭。知道我缺少什么吗?

我有一个带有连接方法的课程,我正在启动其中的线程,调用它,加入它,我希望该线程在该线程中运行背景和程序执行将继续,但是它挂在我的连接_to方法中,直到线程执行停止

这实际上是加入线程应该做的!

如果您不想加入线程,那么简单地不。:)

,可能,您可能至少应该在类驱动器或其他某些时间中进行此操作,以便您的主线程在工作线程仍在执行时无法尝试结束。因为那将以眼泪结束...

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

它正在悬挂,因为对join()的调用导致当前线程被暂停,直到连接线程完成为止,直到join()的调用将返回。

 conn_thread.join();   // Current thread will wait
                       // until conn_thread finishes.

您还在评论中提到,如果您不进行加入,那么您会得到一个堕胎。这是因为线程的破坏者调用terminate()如果其代表的线程仍然是joinble

由于您的线程对象是本地的,因此在呼叫Connect_to()的末尾被销毁。

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

中有一个成员
thread*               m_conn_thread;

这似乎没有使用。
如果将线程存储在此对象中,它将持续到对象(因此比函数更长)。由于对象的线程访问成员,因此对象显然应该持续使用。

所以我将进行以下更改:

 // 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.
  }