Running a thread in the background in C ++ 11

I have a class with a connect_to method that I start a thread in it, after calling it and attaching to it, I expected the thread to run in the background and program execution would continue, but it hangs in mine connect_to

until the thread execution stops. I remember that I was working with threads in C # and they were running in the background when I started them.

#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

      

The thread works as intended and is in a canned cycle until the connection is closed. Any idea what I'm missing?

+3


source to share


2 answers


It hangs because the call join()

causes the current thread to pause until the connection thread finishes, at which point the call will return join()

.

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

      

You also point out in the comments that if you don't make the connection, you will get an interrupt triggered. This is because the thread's destructor is called terminate()

if the thread it represents is still joinble

.

Since your thread object is local, it is destroyed at the end of the call 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()`

      

So how do you stop this.

  • You can call the method detach()

    .
  • You can make it thread

    belong to a larger context so that it is not destroyed.


Calling is detach()

not a good idea. As you lose all link to the current stream and communication with it becomes difficult.

I also notice that you have a dick in class TCPClient

thread*               m_conn_thread;

      

This doesn't seem to be used.
If you keep the stream in this object, it will last as long as the object (thus longer than a function). The object is supposed to continue as long as the stream is from the moment the object's stream is accessed.

So, I would make the following changes:

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


source


I have a class with a connect_to method that I start with it in the thread, after and attach to it , I expected the thread to start in the background and the program execution would continue, but it hangs in my connect_to method until thread execution won't stop

This is literally what a stream join is supposed to do!

If you don't want to join the stream, just don't. :)



Although, you should probably at least do this in your class destructor or at some other point in time so that your main thread cannot exit while the worker thread is still running. Because it will end in tears ...

It seems to me that this is a great example of why we shouldn't write lines of code without understanding why we are doing it. :) You made an assumption about what it means conn_thread.join()

, an assumption that it is wrong: one of the first things to do in this situation, read the documentation to make sure your assumptions hold. Ideally, you would read it before writing the code, but never mind.

+7


source







All Articles