我正在尝试使用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循环?
答案1
在 2.26 之前的 GNU libc 版本以及包括 x86_64 在内的某些架构上,从传递给 的函数返回后clone()
,libc 最终将调用exit_group()
(返回值作为参数,您不传递因此随机 16),这将导致所有线程(整个进程)终止。
commit 3f823e87ccbf3723eb4eeb63b0619f1a0ceb174e Author: Adhemerval Zanella <[email protected]> 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)
) 而不是使用 来解决这个return
问题,或者如果您不想修改函数,请将包装函数传递给clone()
定义为:
int wrapper(void *arg)
{
syscall(SYS_exit, t2_thread(arg));
return 0; /* never reached */
}