2012-09-03 26 views
1

下面是我的程序是应该做的:进程被杀死没有(明显)原因和程序停止工作

创建4点孩子的过程:

进程0是在从标准输入一次读取1个字节,然后将其写入到FIFO

过程1从FIFO读这个1个字节和其作为HEX值写入到共享存储器中

过程图2是从共享存储器读HEX值,并将其写入到管

最后处理3由管读出和写入到STDOUT(在我的情况:终端)

我不能改变通信信道。先进先出,共享内存,然后管道是唯一的选择。

我的问题:程序随机时刻停止时,一些文件被引导到标准输入(例如:./程序<的/ dev/urandom的)。有时在编写5个十六进制值之后,有时会在100之后。奇怪的是,当它工作并且在另一个终端中时,我写了“pstree -c”,有一个主进程和4个子进程(这是我想要的),但是当我在停止写入(但仍然运行)后写入“pstree -c”,则只有3个子进程。出于某种原因,即使他们都有(1)在他们中间,但1仍然消失。

我想我可能在这里有同步问题,但我无法发现它(我试了很多个小时)。

下面的代码:

#include <unistd.h> 
#include <fcntl.h> 
#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include <sys/shm.h> 
#include <sys/sem.h> 
#include <sys/types.h> 
#include <sys/wait.h> 
#include <sys/stat.h> 
#include <string.h> 
#include <signal.h> 

#define BUFSIZE 1 
#define R 0 
#define W 1 

// processes ID 
pid_t p0, p1, p2, p3; 

// FIFO variables 
int fifo_fd; 
unsigned char bufor[BUFSIZE] = {}; 
unsigned char bufor1[BUFSIZE] = {}; 

// Shared memory variables 
key_t key; 
int shmid; 
char * tab; 

// zmienne do pipes 
int file_des[2];   
char bufor_pipe[BUFSIZE*30] = {}; 

void proces0() 
{ 
ssize_t n; 

while(1) 
{  
    fifo_fd = open("/tmp/fifo",O_WRONLY);      

    if(fifo_fd == -1) 
    { 
     perror("blad przy otwieraniu kolejki FIFO w p0\n"); 
     exit(1); 
    } 

    n = read(STDIN_FILENO, bufor, BUFSIZE);    

    if(n<0) 
    { 
     perror("read error w p0\n"); 
     exit(1); 
    } 

    if(n > 0) 
    { 
     if(write(fifo_fd, bufor, n) != n) 
     { 
      perror("blad zapisu do kolejki fifo w p0\n"); 
      exit(1); 
     } 

     memset(bufor, 0, n);         // czyszczenie bufora  
    } 

    close(fifo_fd);  
} 

} 

void proces1() 
{ 
ssize_t m, x; 
char wartosc_hex[30] = {}; 

while(1) 
{ 
    if(tab[0] == 0) 
    {  
     fifo_fd = open("/tmp/fifo", O_RDONLY);      // otwiera plik typu fifo do odczytu 

     if(fifo_fd == -1) 
     { 
      perror("blad przy otwieraniu kolejki FIFO w p1\n"); 
      exit(1); 
     } 

     m = read(fifo_fd, bufor1, BUFSIZE); 
     x = m; 

     if(x < 0) 
     { 
      perror("read error p1\n"); 
      exit(1); 
     } 

     if(x > 0) 
     {  
      // Konwersja na HEX 

      if(bufor1[0] < 16) 
      { 
       if(bufor1[0] == 10)  // gdy enter 
       { 
        sprintf(wartosc_hex, "0x0%X\n", bufor1[0]); 
       } 
       else 
       { 
        sprintf(wartosc_hex, "0x0%X ", bufor1[0]); 
       } 
      } 
      else 
      { 
       sprintf(wartosc_hex, "0x%X ", bufor1[0]); 
      } 

      // poczekaj az pamiec bedzie pusta (gotowa do zapisu) 

      strcpy(&tab[0], wartosc_hex); 
      memset(bufor1, 0, sizeof(bufor1));         // czyszczenie bufora 
      memset(wartosc_hex, 0, sizeof(wartosc_hex));  // przygotowanie tablicy na zapis wartosci hex 
      x = 0; 
     } 

     close(fifo_fd);  
    }   
} 
} 

void proces2() 
{ 
close(file_des[0]);  // zablokuj kanal do odczytu 

while(1) 
{ 
    if(tab[0] != 0) 
    { 
     if(write(file_des[1], tab, strlen(tab)) != strlen(tab)) 
     { 
      perror("blad write w p2"); 
      exit(1); 
     } 

     // wyczysc pamiec dzielona by przyjac kolejny bajt 
     memset(tab, 0, sizeof(tab)); 
    } 
} 
} 

void proces3() 
{ 
ssize_t n; 

close(file_des[1]);  // zablokuj kanal do zapisu 

while(1) 
{ 
    if(tab[0] == 0) 
    { 
    if((n = read(file_des[0], bufor_pipe, sizeof(bufor_pipe))) > 0) 
    { 
     if(write(STDOUT_FILENO, bufor_pipe, n) != n) 
     { 
      perror("write error w proces3()"); 
      exit(1); 
     } 

     memset(bufor_pipe, 0, sizeof(bufor_pipe)); 
    } 
} 
} 
} 

int main(void) 
{ 
key = 5678; 
int status; 

// Tworzenie plikow przechowujacych ID procesow 

int des_pid[2] = {}; 
char bufor_proces[50] = {}; 

mknod("pid0", S_IFREG | 0777, 0); 
mknod("pid1", S_IFREG | 0777, 0); 
mknod("pid2", S_IFREG | 0777, 0); 
mknod("pid3", S_IFREG | 0777, 0); 

// Tworzenie semaforow 

key_t klucz; 
klucz = ftok(".", 'a');     // na podstawie pliku i pojedynczego znaku id wyznacza klucz semafora 

if(klucz == -1) 
{ 
    perror("blad wyznaczania klucza semafora"); 
    exit(1); 
} 

semafor = semget(klucz, 1, IPC_CREAT | 0777);   // tworzy na podstawie klucza semafor. 1 - ilosc semaforow 

if(semafor == -1) 
{ 
    perror("blad przy tworzeniu semafora"); 
    exit(1); 
} 

if(semctl(semafor, 0, SETVAL, 0) == -1)       // ustawia poczatkowa wartosc semafora (klucz, numer w zbiorze od 0, polecenie, argument 0/1/2) 
{ 
    perror("blad przy ustawianiu wartosci poczatkowej semafora"); 
    exit(1); 
} 

// Tworzenie lacza nazwanego FIFO 

if(access("/tmp/fifo", F_OK) == -1)        // sprawdza czy plik istnieje, jesli nie - tworzy go 
{ 
    if(mkfifo("/tmp/fifo", 0777) != 0) 
    { 
     perror("blad tworzenia FIFO w main"); 
     exit(1); 
    } 
} 

// Tworzenie pamieci dzielonej 
// Lista pamieci wspoldzielonych, komenda "ipcs" 
// usuwanie pamieci wspoldzielonej, komenta "ipcrm -m ID_PAMIECI" 

shmid = shmget(key, (BUFSIZE*30), 0666 | IPC_CREAT); 

if(shmid == -1) 
{ 
    perror("shmget"); 
    exit(1); 
} 

tab = (char *) shmat(shmid, NULL, 0); 

if(tab == (char *)(-1)) 
{ 
    perror("shmat"); 
    exit(1); 
} 

memset(tab, 0, (BUFSIZE*30)); 

// Tworzenie lacza nienazwanego pipe 

if(pipe(file_des) == -1) 
{ 
    perror("pipe"); 
    exit(1); 
} 

// Tworzenie procesow potomnych 
if(!(p0 = fork())) 
{ 
    des_pid[W] = open("pid0", O_WRONLY | O_TRUNC | O_CREAT);     // 1 - zapis, 0 - odczyt 

    sprintf(bufor_proces, "Proces0 ma ID: %d\n", getpid()); 

    if(write(des_pid[W], bufor_proces, sizeof(bufor_proces)) != sizeof(bufor_proces)) 
    { 
     perror("blad przy zapisie pid do pliku w p0"); 
     exit(1); 
    } 

    close(des_pid[W]); 

    proces0(); 
} 
else if(p0 == -1) 
{ 
    perror("blad przy p0 fork w main"); 
    exit(1); 
} 
else 
{ 
    if(!(p1 = fork())) 
    { 
     des_pid[W] = open("pid1", O_WRONLY | O_TRUNC | O_CREAT);     // 1 - zapis, 0 - odczyt 

     sprintf(bufor_proces, "Proces1 ma ID: %d\n", getpid()); 

     if(write(des_pid[W], bufor_proces, sizeof(bufor_proces)) != sizeof(bufor_proces)) 
     { 
      perror("blad przy zapisie pid do pliku w p1"); 
      exit(1); 
     } 

     close(des_pid[W]); 

     proces1(); 
    } 
    else if(p1 == -1) 
    { 
     perror("blad przy p1 fork w main"); 
     exit(1); 
    } 
    else 
    { 
     if(!(p2 = fork())) 
     { 
      des_pid[W] = open("pid2", O_WRONLY | O_TRUNC | O_CREAT);     // 1 - zapis, 0 - odczyt 

      sprintf(bufor_proces, "Proces2 ma ID: %d\n", getpid()); 

      if(write(des_pid[W], bufor_proces, sizeof(bufor_proces)) != sizeof(bufor_proces)) 
      { 
       perror("blad przy zapisie pid do pliku w p2"); 
       exit(1); 
      } 

      close(des_pid[W]); 
      proces2(); 
     } 
     else if(p2 == -1) 
     { 
      perror("blad przy p2 fork w main"); 
      exit(1); 
     } 
     else 
     { 
      if(!(p3 = fork())) 
      { 
       des_pid[W] = open("pid3", O_WRONLY | O_TRUNC | O_CREAT);     // 1 - zapis, 0 - odczyt 

       sprintf(bufor_proces, "Proces3 ma ID: %d\n", getpid()); 

       if(write(des_pid[W], bufor_proces, sizeof(bufor_proces)) != sizeof(bufor_proces)) 
       { 
        perror("blad przy zapisie pid do pliku w p3"); 
        exit(1); 
       } 

       close(des_pid[W]); 

       proces3(); 
      } 
      else if(p3 == -1) 
      { 
       perror("blad przy p3 fork w main"); 
       exit(1); 
      } 
      else 
      { 
       // proces macierzysty 
       waitpid(p0, &status, 0); 
       waitpid(p1, &status, 0); 
       waitpid(p2, &status, 0); 
       waitpid(p3, &status, 0); 
       //wait(NULL); 
       unlink("/tmp/fifo"); 
       shmdt(tab);        // odlaczenie pamieci dzielonej 
       shmctl(shmid, IPC_RMID, NULL);   // usuwanie pamieci wspoldzielonej 
       printf("\nKONIEC PROGRAMU\n"); 
      } 
     } 
    } 
} 

exit(0); 
} 

使用 “strace的./projekt_wlasciwy <的/ dev/urandom的” 我有这样的事情后:

clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD,  child_tidptr=0xb7e2e728) = 26916 
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD,  child_tidptr=0xb7e2e728) = 26917 
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD,  child_tidptr=0xb7e2e728) = 26918 
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD,  child_tidptr=0xb7e2e728) = 26919 
waitpid(26916, 0xAA 0xC1 0x84 0x9C 0x4E 0x0D 0x54 0xB2 0xE7 0x19 0x22 0xA0 0x2E 0xF0 0x1C 0xC4 0xDF 0x21 0xA2 0xB4 0x3B 0xEE [{WIFSIGNALED(s) && WTERMSIG(s) == SIGPIPE}], 0) = 26916 
--- SIGCHLD (Child exited) @ 0 (0) --- 
waitpid(26917, 0x40 0xbfb083a8, 0)   = ? ERESTARTSYS (To be restarted) 
--- SIGWINCH (Window changed) @ 0 (0) --- 
waitpid(26917, [{WIFSIGNALED(s) && WTERMSIG(s) == SIGTERM}], 0) = 26917 
--- SIGTERM (Terminated) @ 0 (0) --- 
+++ killed by SIGTERM +++ 
+2

这是功课吗? – squiguy

+1

如果可能的话,用英语评论会更有礼貌。 – unwind

+2

您是否编译过所有的警告和调试信息(即'gcc -Wall -g')?你尝试调试你的程序吗?你用'strace'来理解系统调用是做什么的? 1的BUFSIZE奇怪。 –

回答

0

有可能是在一个错误你的代码会让其中一个孩子崩溃。我建议添加一些调试输出(将其写入控制台或日志文件),以便您可以查看数据传入和传出的内容。

我也有点担心的输出。 ERESTARTSYS表示有一个系统调用可以重新启动(=再试一次)。不知道从哪里来。

另外SIGTERM意味着有人杀死了这个过程。但是,那可能是strace告诉你,你停止了它。如果它是其中一个孩子的输出,那么有人会杀死你的过程。

+0

是的,有一个错误,我认为我已经发现了 - process0从stdin不断读取,而process3只是在很长时间才写入stdout,因为它正在等待process1和process2传递数据。那些来自stdin的readen字符必须存储在某处,并且process0必须被OOM杀死,我认为是因为它使用了太多的内存。 – Celebes

2

代码中有一些与信号量相关的错误。您的代码中有读者(process2)和作者(process1)。

他们需要独占访问共享内存,这是不正确的。您正在使用

semctl(semafor, 0, SETVAL, 0) == -1 

看来,这是不正确。你正试图为信号量设置一些值。在这种情况下检查第四个参数。 P1。从链接中读取http://pubs.opengroup.org/onlinepubs/7908799/xsh/semctl.html

此外,在共享内存中执行某些操作之前,您还需要检查process1和process2中的信号量值。这些业务在哪里?你需要使用丢失的semop。 PL。阅读链接http://pubs.opengroup.org/onlinepubs/7908799/xsh/semop.html

+0

不完全是,信号量可能会被严重实施,但从未被使用过,因为稍后当我需要添加停止/保持/运行等信号时,我需要它们。 – Celebes