The system() function isn't necessarily thread-safe.
POSIX.1-2008 specifies (as well as POSIX.1-2001):
The system() function need not be thread-safe.
For example, Solaris 10 documents system() as thread-unsafe:
The system() function manipulates the signal handlers for
SIGINT, SIGQUIT, and SIGCHLD. It is therefore not safe to
call system() in a multithreaded process, since some other
thread that manipulates these signal handlers and a thread
that concurrently calls system() can interfere with each
other in a destructive manner.
This man page also suggests popen() as thread-safe work-around. Note that popen() doesn't change any signal handlers.
On Linux, system() is thread-safe.
Note that system() doesn't necessarily calls fork(). A implementation could use vfork(), instead. Or, on Linux, it could directly call clone(). It could even use posix_spawn().
Although forking in a multi-threaded program can be challenging, a fork directly followed by an exec is safe, in general (modulo open file descriptors).