Linux-Kernel
為什麼此程式碼以返回碼 16 退出?
我正在嘗試使用 clone() 系統呼叫來創建執行緒。然而,程序在從 t2_thread() 函式返回時自行終止。為什麼會出現這種行為?我錯過了什麼?
#define _GNU_SOURCE #include<sys/syscall.h> #include<stdio.h> #include<unistd.h> #include<stdlib.h> #include<errno.h> #include<sched.h> int t2_thread(void *arg) { printf("Thread 2 (%ld)\n",syscall(SYS_gettid)); return; } int main(int argc, char **argv) { const size_t STCK_SZ = 65536; char *stck; int flags; stck = malloc(STCK_SZ); if(stck == NULL) { perror("malloc"); exit(EXIT_FAILURE); } flags = CLONE_SIGHAND |CLONE_FS |CLONE_VM |CLONE_FILES | CLONE_THREAD; if(clone(t2_thread, stck + STCK_SZ, flags, NULL)==-1) { perror("clone"); exit(EXIT_FAILURE); } printf("Thread 1 (%ld)\n",syscall(SYS_gettid)); for(;;) { printf("T1\n"); sleep(1); } exit(EXIT_SUCCESS); }
順便說一下,這個程序的輸出是:
Thread 1 (8963) T1 Thread 2 (8964) $echo $? 16
我應該怎麼做才能無限執行for循環?
在 2.26 之前的 GNU libc 版本和包括 x86_64 在內的某些架構中,從傳遞給的函式返回時
clone()
,libc 最終會呼叫exit_group()
(將返回的值作為您不傳遞的參數,因此隨機 16)這將導致所有執行緒(整個程序)終止。commit 3f823e87ccbf3723eb4eeb63b0619f1a0ceb174e Author: Adhemerval Zanella <adhemerval.zanella@linaro.org> Date: Thu Jun 22 08:49:34 2017 -0300 Call exit directly in clone (BZ #21512) On aarch64, alpha, arm, hppa, mips, nios2, powerpc, sh, sparc, tile, and x86_64 the clone syscall jumps to _exit after the child execution and the function ends the process execution by calling exit_group. This behavior have a small issue where threads created with CLONE_THREAD using clone syscall directly will eventually exit the whole group altogether instead of just the thread created. Also, s390, microblaze, ia64, i386, and m68k differs by calling exit syscall directly. This patch changes all architectures to call the exit syscall directly, as for s390, microblaze, ia64, i386, and m68k. This do not have change glibc internal behavior in any sort, since the only usage of clone implementation in posix_spawn calls _exit directly in the created child (fork uses a direct call to clone). Checked on x86_64-linux-gnu, i686-linux-gnu, aarch64-linux-gnu, powerpc-linux-gnu, powerpc64le-linux-gnu, sparc64-linux-gnu, and sparcv9-linux-gnu.
對於舊版本,您可以通過
exit
直接呼叫系統呼叫 (syscall(SYS_exit, 0)
) 而不是 using 來解決它return
,或者如果您不想修改函式,請將包裝函式傳遞給clone()
定義為:int wrapper(void *arg) { syscall(SYS_exit, t2_thread(arg)); return 0; /* never reached */ }