Tôi đã xem xét cam kết mà Ulrich Drepper đã thêm mã đó vào glibc và không có bất kỳ lời giải thích nào trong nhật ký cam kết (hoặc ở nơi khác).
Hãy nhìn vào thực hiện fork
Linux, mặc dù:
return _do_fork(SIGCHLD, 0, 0, NULL, NULL, 0);
Và đây là clone
:
return _do_fork(clone_flags, newsp, 0, parent_tidptr, child_tidptr, tls);
Rõ ràng, họ gần như giống hệt nhau. Sự khác biệt duy nhất là khi gọi clone
, bạn có thể đặt các cờ khác nhau, có thể chỉ định kích thước ngăn xếp cho quy trình mới, v.v. fork
không nhận bất kỳ đối số nào.
Nhìn vào mã của Drepper, cờ clone
là CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD
. Nếu sử dụng fork
, cờ duy nhất sẽ là SIGCHLD
.
Dưới đây là những gì các clone
manpage nói về những lá cờ thêm:
CLONE_CHILD_CLEARTID (since Linux 2.5.49)
Erase child thread ID at location ctid in child memory when the child
exits, and do a wakeup on the futex at that address. The address
involved may be changed by the set_tid_address(2) system call. This is
used by threading libraries.
CLONE_CHILD_SETTID (since Linux 2.5.49)
Store child thread ID at location ctid in child memory.
... Và bạn có thể thấy rằng anh ta vượt qua một con trỏ đến nơi hạt nhân đầu tiên nên lưu trữ thread ID của trẻ và sau đó làm một cuộc đánh thức futex. Glibc có đang chờ đợi futex trên địa chỉ đó ở đâu đó không? Tôi không biết. Nếu vậy, điều đó sẽ giải thích tại sao Drepper lại chọn sử dụng clone
.
(Và nếu không, nó sẽ chỉ là một ví dụ nữa về sự tích tụ cực đại của tàu tuần dương là glibc yêu quý của chúng tôi! Nếu bạn muốn tìm một số mã đẹp, sạch, được bảo trì tốt, hãy tiếp tục di chuyển và đi nhìn vào musl libc!)
'pthread_join()' thực hiện việc đánh thức. Tương tự như thế nào, nếu bạn liên kết với các chủ đề, glibc gọi 'set_tid_address()' để chủ đề "chính" có thể được nối: http://stackoverflow.com/questions/6975098/when-is-the-system-call-set -tid-address-used – ninjalj
@usr: quá trình mới có thể sinh ra các luồng. Nếu bạn muốn các luồng đó có thể 'pthread_join()' trên luồng chính của tiến trình mới, glibc cần địa chỉ của futex. – ninjalj
@usr: 'execve()' xử lý điều đó bằng cách gọi 'set_tid_address()'. BTW, nếu bạn ngay lập tức exec, có 'vfork()', hoặc 'posix_spawn()', nếu libc của bạn cung cấp điều đó. – ninjalj