2

I'm working on a C++ project which employs pthreads for multithreading, but also needs to fork now and then. I've read warnings scattered in the code that memory allocation should never be done after fork, but I didn't know exactly why before I found this article. I've summarized the points:

  1. When the main thread forks, the other threads may be in the middle of some library function call; forking doesn't copy the other threads, making the calls stuck forever;

  2. malloc uses global variable, and employs locks to achieve thread safety. So if one of threads of the parent process happen to be in the middle in a malloc call, the forked child process has effectively a malloc call stuck forever that can never recover. Same thing for printf, etc.

I realized that this has something to do with reentrancy, a term that is not mentioned in the article. It seems that the claim is equivalent to:

  1. If you called some non-entrant function f off the main thread in the parent process, the child process can not call f.

  2. malloc is non-reentrant.

Is this correct, meaning that all reentrant functions may be safely used after forking? Or am I still missing some nasty corners of how pthreads and traditional UNIX process model interact?

If I am right, there is another question: malloc is known to be non-reentrant, but what about C++'s new? I googled for that with not many relevant results (mostly due to the difficulty to hit the correct "new" :), but there is at least one claim that new is reentrant. There is also a relevant question concerning the whole C++ standard library with no satisfying answer.

PS. For the interested, the C++ project is the fish shell. Forking is definitely needed for shells, and threads are employed to improve responsiveness.

Community
  • 1
  • 1
xiaq
  • 764
  • 1
  • 6
  • 13
  • Reentrancy *is* mentioned in the thread: it mentions "async-safe functions". – cnicutar Dec 30 '12 at 11:43
  • @cnicutar I didn't find "async-safe" on Wikipedia, so I take it to be a synonym of thread-safe. `f` is thread-safe if you can safely call `f` in thread A while thread B is in the middle of a `f` call. `f` is reentrant is you can call it in thread B and expect it *never blocks*. Thus using locks to guard `f` calls, block the `f` call in thread A until the call in thread B finishes **is** an acceptable way to achieve thread safety, but it is **not** reentrant. – xiaq Dec 30 '12 at 11:44
  • Thing is "async-safe" means reentrant not thread-safe. – cnicutar Dec 30 '12 at 11:47
  • @cnicutar According to [this article](http://www.ibm.com/developerworks/linux/library/l-reent/index.html), reentrant functions are always async-free, but not the opposite. That concludes my main question. I'll ask the additional one in another thread. :) – xiaq Dec 30 '12 at 11:53
  • @cnicutar perhaps you can put your (short) answer in the answer area. ;) – xiaq Dec 30 '12 at 11:54
  • I think you answered your own question, and taught me something in the process. You should answer your own question; I'd upvote. – cnicutar Dec 30 '12 at 11:55
  • There are some issues raised in the [rationale](http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_atfork.html) for `pthread_atfork` that you might find interesting. – Brett Hale Dec 30 '12 at 12:01
  • AFAICT, the gnu libc malloc implementation has `atfork` handlers that appear to handle this sort of thing by ensuring the state is consistent before and after forking. This might not be the general case though – Hasturkun Dec 30 '12 at 12:35

1 Answers1

2

As pointed out by @cnicutar, the article did mention that you can call async-safe functions after forking. And according to this article, reentrant functions are always async-free (but not the opposite), thus safe to call after forking.

That concludes my main question. I'll ask the additional question in another thread (no pun intended).

Updated: I asked the additional question here.

Community
  • 1
  • 1
xiaq
  • 764
  • 1
  • 6
  • 13