and it works without the AUTOFLUSH in LOG.
seek apparently forces a flush. Assuming it's safe to rely on that, it's not good enough. The catch is that it's forcing the flush at the wrong time. You want to flush immediately after the print, not at the start of the thread's next print.
and it works without the lock in $sem
You're relying on your OS to do writes atomically. That might be reliable for small writes, but why chance it. If you do find a performance bottleneck, you might be better off using a separate log file for each thread and merge them later.