7

When doing socket programming, with multi-threading,

if a thread is blocked on Accept Function,

and main thread is trying to shut down the process,

how to break the accept function in order to pthread_join safely?

I have vague memory of how to do this by connection itself to its own port in order to break the accept function.

Any solution will be thankful.

Cheers

Jae Park
  • 621
  • 4
  • 13
  • 27
  • 3
    Wouldn't it be easier just to use non-blocking sockets instead? – Tony The Lion Sep 24 '12 at 12:34
  • 2
    It might be a lot easier to use non-blocking sockets. You don't even need multithreading, since simple IO multiplexing (e.g. with `epoll` or `kqueue`) can handle a *lot* of IO. – Kerrek SB Sep 24 '12 at 12:35
  • Yeah seems like nonblocking is the easiest way to fix this. Thank you all :D – Jae Park Sep 24 '12 at 12:46
  • Well, the OP does not provide any information on overall functionality/loading to suggest that a non-blocking, single-threaded approach will provide sufficient performance. Still, if the OP can accept the level of performance from a single-threaded solution, fine. – Martin James Sep 24 '12 at 13:30
  • Answered here: https://stackoverflow.com/a/62356967/70405 . Don't mind the boost involvement, solution is at socket API level. – Alex Jun 13 '20 at 09:25
  • Does this answer your question? [Boost::asio - how to interrupt a blocked tcp server thread?](https://stackoverflow.com/questions/11191028/boostasio-how-to-interrupt-a-blocked-tcp-server-thread) – Alex Jun 13 '20 at 09:28

6 Answers6

3

Some choices:

a) Use non-blocking

b) Use AcceptEx() to wait on an extra signal, (Windows)

c) Close the listening socket from another thread to make Accept() return with an error/exception.

d) Open a temporary local connection from another thread to make Accept() return with the temp connection

Martin James
  • 24,453
  • 3
  • 36
  • 60
  • 1
    I have found that (c) doesn't work reliably. But using `shutdown()` instead of `close()` does. See https://stackoverflow.com/a/9365357/2744934. – Mike Spear Mar 23 '19 at 00:27
1

The typical approach to this is not to use accept() unless there is something to accept! The way to do this is to poll() the corresponding socket with a suitable time-out in a loop. The loop checks if it is meant to exit because a suitably synchronized flag was set.

An alternative is to send the blocked thread a signal, e.g., using pthread_kill(). This gets out of the blocked accept() with a suitable error indication. Again, the next step is to check some flag to see if the thread is meant to exit. My preference is the first approach, though.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • 1
    Tempted to downvote this for suggesting a polling solution, but as it will work-ish, I will resist:) – Martin James Sep 24 '12 at 13:26
  • @MartinJames: What is wrong with using `poll()`? It is my understanding that this is _the_ [portable] way to do I/O multiplexing. What else would you use? – Dietmar Kühl Sep 24 '12 at 13:46
  • @Canadian_Republican: both `select()` and `poll()` take a time-out parameter (as a `struct timeval`) or an `int`. `poll()` is much preferable over `select()` (and where available the `epoll*()` is, yet, preferable when monitoring multiple file descriptors). – Dietmar Kühl Apr 14 '16 at 20:52
  • @DietmarKühl Any chance you can point me to an example of a poll() within a thread? I'm still learning. – Rahim Khoja Apr 15 '16 at 04:47
  • @Canadian_Republican: there is nothing special about calling `poll()` from a thread. ... and there is no chance that I'll search for examples for you (that wouldn't change even if you'd tried to pay me unless you offer ludicrous amounts as this work isn't something I'm interested in doing). – Dietmar Kühl Apr 15 '16 at 10:39
1

Depending on your system, if it is available, I would use a select function to wait for the server socket to have a read, indicating a socket is trying to connect. The amount of time to time to wait for a connection can be set/adjusted to to what every time you want to wait for a client to connect(infinity, to seconds, to 0 which will just check and return). The return status needs to be checked to see if the time limit was reached (no socket is trying to connect), or if there is something waiting to be serviced (your server socket indicating there is a client which would like to connect). You can then execute the accept knowing there is a socket to connect based on the returned status.

Glenn
  • 1,169
  • 1
  • 14
  • 23
1

If available I would use a select function with a timeout in a loop to achieve this functionality.

as Glenn suggested

The select function with a timeout value will wait for a socket to connect for a set period of time. If a socket attempts to connect it can be accepted during that period. By looping this select with a timeout it is possible to check for new connections until the break condition is met.

Here is an example:

std::atomic<bool> stopThread;
void theThread ( std::atomic<bool> & quit )
{
    struct timeval tv;
    int activity;
    ...
    while(!quit) 
    {
        // reset the time value for select timeout
        tv.tv_sec = 0;
        tv.tv_usec = 1000000;
        ...

        //wait for an activity on one of the sockets
        activity = select( max_sd + 1 , &readfds , NULL , NULL , &tv);

        if ((activity < 0) && (errno!=EINTR)) 
        {
            printf("select error");
        }

        if (FD_ISSET(master_socket, &readfds)) 
        {
            if ((new_socket = accept(master_socket, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0)
            {
                perror("accept");
                exit(EXIT_FAILURE);
            }
       ...
    }
}

int main(int argc, char** argv)
{
...
stopThread = false;
std::thread foo(theThread, std::ref(stopThread));
...    

stopThread = true;
foo.join();
return 0;

}

A more complete example of 'Select' http://www.binarytides.com

I am pretty new to C++ so I am sure my code and answer can be improved.

Rahim Khoja
  • 695
  • 13
  • 26
  • 1
    A timeout wastes CPU cycles and makes the response time slower (e.g. in your example it would add up to an additional second to the program's shutdown time). A better solution would be to create a socketpair or pipe at startup and have the thread select() on one of the sockets (in addition to its other sockets). Then when the main thread wants to shut everything down, the main thread can write a byte to the other socket; that will cause the other thread's select() call to return, and when it sees that there is a byte on the pipe/socketpair it knows to exit ASAP. – Jeremy Friesner Apr 14 '16 at 21:32
  • @JeremyFriesner I'm still really new to c++ do you think you can show me an example of a socket pair with a select? – Rahim Khoja Apr 15 '16 at 04:33
  • 1
    Sure... see this URL: http://www.lcscanada.com/jaf/socketpair_example.cpp <-- in this very simple example, the spawned thread does nothing except wait in select() until the main thread sends a byte across the socketpair (after the user pressed return); then the spawned thread sees that its socket has become ready-for-read and reacts by exiting immediately so that the main thread can finish shutting down. (Note: tested on MacOS/X, should also work under Linux/Unix; to work under Windows requires a windows implementation of socketpair()) – Jeremy Friesner Apr 15 '16 at 05:25
0

Sounds like what you are looking for is this: You set a special flag variable known to the listening/accepting socket, and then let the main thread open a connection to the listening/accepting socket. The listening/accepting socket/thread has to check the flag every time it accepts a connection in order to know when to shut down.

Seg Fault
  • 1,331
  • 8
  • 16
  • But what if the flag was set while it was listening and there will never be a connection? – Daniel Sep 24 '12 at 12:39
  • Dani's comment is the situation... I found nonblock as solution thanks – Jae Park Sep 24 '12 at 12:57
  • @Dani That's why the thread shutting down everything (briefly) opens a connection, to trigger looking at the flag. – Seg Fault Sep 24 '12 at 13:07
  • The nonblocking socket is also a solution, it basically depends on the overall threading model, i.e. whether you want one thread to handle many (listen) sockets, or one thread per socket... – Seg Fault Sep 24 '12 at 13:09
  • This is a reasonable solution, so why downvote it? Adding an upvote. – Martin James Sep 24 '12 at 13:24
-2

Typically if you want to do multi-threaded networking, you would spawn a thread once a connection is made (or ready to be made). If you want to lower the overhead, a thread pool isn't too hard to implement.

std''OrgnlDave
  • 3,912
  • 1
  • 25
  • 34