2017-01-11 2 views
0

Простой тестовой программы, я ожидаю, что это будет «клон» раскошелиться дочерним процесс, и каждый процесс может выполнять до его концаCalling «клон()» на Linux, но это, кажется, сбои

#include<stdio.h> 
#include<sched.h> 
#include<unistd.h> 
#include<sys/types.h> 
#include<errno.h> 
int f(void*arg) 
{ 
pid_t pid=getpid(); 
printf("child pid=%d\n",pid); 
} 
char buf[1024]; 
int main() 
{ 
    printf("before clone\n"); 
    int pid=clone(f,buf,CLONE_VM|CLONE_VFORK,NULL); 
    if(pid==-1){ 
     printf("%d\n",errno); 
     return 1; 
    } 
    waitpid(pid,NULL,0); 
    printf("after clone\n"); 
    printf("father pid=%d\n",getpid()); 
    return 0; 
} 

Ru его:

$g++ testClone.cpp && ./a.out 
before clone 

Это не печатало то, что я ожидал. Кажется, что после «клонирования» программа находится в неизвестном состоянии, а затем завершает работу. Я попытался GDB и печатает:

Breakpoint 1, main() at testClone.cpp:15 
(gdb) n- 
before clone 
(gdb) n- 
waiting for new child: No child processes. 
(gdb) n- 
Single stepping until exit from function [email protected],- 
which has no line number information. 

Если удалить строку «waitpid», затем GDB печатает другой вид странной информации.

(gdb) n- 
before clone 
(gdb) n- 
Detaching after fork from child process 26709. 
warning: Unexpected waitpid result 000000 when waiting for vfork-done 
Cannot remove breakpoints because program is no longer writable. 
It might be running in another process. 
Further execution is probably impossible. 
0x00007fb18a446bf1 in clone() from /lib64/libc.so.6 
ptrace: No such process. 

Где я ошибался в своей программе?

ответ

1

Второй аргумент clone является указателем на стек дочернего элемента. Согласно странице руководства clone(2): растут вниз

стеков на всех процессорах, которые работают Linux (кроме процессоров HP PA), так что child_stack обычно указывает на верхний адрес в пространстве памяти, которое устанавливается для стека ребенка.

Кроме того, 1024 байта - это ничтожная сумма для стека. Следующая модифицированная версия вашей программы, как представляется, правильно работать:

// #define _GNU_SOURCE // may be needed if compiled as C instead of C++ 
#include <stdio.h> 
#include <sched.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/wait.h> 
#include <errno.h> 

int f(void*arg) 
{ 
    pid_t pid=getpid(); 
    printf("child pid=%d\n",pid); 
    return 0; 
} 
char buf[1024*1024]; // *** allocate more stack *** 
int main() 
{ 
    printf("before clone\n"); 
    int pid=clone(f,buf+sizeof(buf),CLONE_VM|CLONE_VFORK,NULL); 
     // *** in previous line: pointer is to *end* of stack *** 
    if(pid==-1){ 
     printf("%d\n",errno); 
     return 1; 
    } 
    waitpid(pid,NULL,0); 
    printf("after clone\n"); 
    printf("father pid=%d\n",getpid()); 
    return 0; 
} 

Кроме того, @Employed России прав - вы, вероятно, не следует использовать clone за исключением, если вы пытаетесь повеселиться. Либо fork, либо vfork - более разумные интерфейсы к clone всякий раз, когда они отвечают вашим потребностям.

2

Вы никогда не должны звонить clone в программу уровня пользователя - существует слишком много ограничений на то, что вам разрешено делать в процессе clone d.

В частности, вызов любой libc функции (например, printf) не является полным нет-нет (потому что libc не знает, что ваш clone существует, и не выполняются какие-либо настройки для него).

Как указывает К. А. Бур, вы также пропускаете слишком маленький стек и неправильный его конец. Ваш стек также неправильно выровнен.

Короче говоря, хотя модификация К. А. Бура появляется, чтобы работать, на самом деле это не так.

TL; clone, только не использовать.

Смежные вопросы