2

I have created a preforking web server which creates the server socket, binds it, listens to an address and port and it preforks a specified number of workers (child processes) which act as workers serving client requests.

All workers inherit the socket descriptor of the parent server and use it to accept client requests. Child processes run as autonomous processes at "parallel" and use accept function with server socket descriptor. Do I have to use lock and unlock mechanism for the accept function when accepting a client request or the operating system does this for me? The idea is here that multiple processes use the common server socket descriptor for accepting client requests. Do I have to shield this with a mutual exclusion mechanism to avoid race conditions or deadlocks?

Please take account that I use I/O nonblocking in the accept function.

I have the following code:

for(;;) {
    int client = accept(...);
    if (client < 0) continue;
    ...
}

Should I use something like:

for(;;) {
    lock();
    int client = accept(...);
    unlock();
    if (client < 0) continue;
    ...
}

??

1 Answers1

3

No. It's a system call, and therefore atomic.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • 3
    This is correct, so I won't add another answer. In the early days, there was the thundering herd problem, and so locks were used to mitigate that problem, but the operation was still atomic. – jxh Jun 25 '14 at 03:47
  • 1
    I have seen this article: http://uwsgi-docs.readthedocs.org/en/latest/articles/SerializingAccept.html. Maybe it is not 100% solved? I might need to take account locking/unlocking? – Efstathios Chatzikyriakidis Jun 25 '14 at 07:12
  • Can anyone tell me if I have to lock before using accept and unlock after it? Or accept is protected from the operating system? – Efstathios Chatzikyriakidis Jun 25 '14 at 15:55
  • 2
    @EfstathiosChatzikyriakidis: The article you cite indicates the thundering herd problem is completely solved for `accept()`, so there is no need for you to lock. It interestingly explains the problem is not solved for demultiplexors (`select()`, `poll()`, etc.), but the common implementation for those calls is that the number of processes waiting on the common FD is limited to the number of CPUs/cores on the platform, so the "herd" is very small. No locks are needed. – jxh Jun 25 '14 at 18:48