如何在C中按顺序执行子进程

如何在C中按顺序执行子进程,c,process,fork,C,Process,Fork,我已经用C写了一个代码来计算文件中的行、字和字符。类似于wc命令。代码如下,运行良好 #include <stdio.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <stdlib.h> char* concat(char *s1, char *s2) { char *result = ma

我已经用C写了一个代码来计算文件中的行、字和字符。类似于
wc
命令。代码如下,运行良好

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>

char* concat(char *s1, char *s2)
{
char *result = malloc(strlen(s1)+strlen(s2)+1);
strcpy(result, s1);
strcat(result, s2);
return result;
} 

int countLines(char *f){
 FILE *file = fopen(f, "r");
int count = 0;
char ch;
while ((ch = fgetc(file)) != EOF){
   if (ch == '\n')
       count++;
}
return count;
}

int countWords(char *f){
char buffer[1];
FILE *file = fopen(f, "r");
  int countW = 0;
  enum states { WSP, WRD };
  int state = WSP;
char last = ' '; 
 while (read(fileno(file),buffer,1) == 1 )
 {
 if ( buffer[0]== ' ' || buffer[0] == '\t' || buffer[0]=='\n' )
 {
    state = WSP;
 }
 else 
 {
    if ( state == WSP )
    {
       countW++;
    }
    state = WRD;
 }
  last = buffer[0];
}
return countW;
}

int countChars(char *f){
 FILE *file = fopen(f, "r");
int chars = 0;
char ch;
while ((ch = fgetc(file))){
     if (ch == EOF) break;
  chars++;
}
return chars;
}

int main(int argc, char** argv)
{
 int lineCount = 0;
 int wordCount = 0;
 int charCount = 0;
 int n = 3;
 int i,status;
 int pids[3];
 char *theprogram = argv[0];
 char *thefile = argv[1];
 if ( argc !=2 )
 {
     printf( "Help: %s filename\n", argv[0]);
 }
 else{
     FILE *file = fopen( argv[1], "r");

   if(file == 0){
         char *sub = concat(theprogram, ": ");
         char *middle = concat(sub, thefile); 
         perror(middle);
   }
   else{
         for (i = 0; i < n; i++) {
             pids[i] = fork();
             if ( pids[i] < 0) { 
                perror("fork"); 
                exit(-1); 
            } else if (pids[i] == 0) { 
                if (i==0){
                        lineCount = countLines(argv[1]);
                        printf("This is child proccess %d, and the number of lines is %d\n", i+1, lineCount);
                        exit(0);
                    }
                    else if (i==1){ 
                        wordCount = countWords(argv[1]);
                        printf("This is child proccess %d, and the number of words is %d\n", i+1, wordCount);
                        exit(0);
                    }
                    else if (i==2){
                        charCount += countChars(argv[1]);
                        printf("This is child proccess %d, and the number of characters is %d\n", i+1, charCount);
                        exit(0);
                    }
            } 
          }
            for(i = 0; i < n; i++){
                wait(NULL);
            }
            return 0;      
            }
 } 
}

第三个过程有时在第二个过程之前结束。如何防止这种情况发生?

分叉的进程将与主线代码异步执行,因此如果希望它们按顺序执行,则需要使用某种标志。这可以是一个信号量、互斥量,或者在if条件中设置一个布尔值


您需要使用信号量或互斥量来保护易受影响的数据不受异步写入的影响,但这在本文中不是问题。

分叉的进程将与主线代码异步执行,因此如果您希望它们按顺序发生,则需要使用某种标志。这可以是一个信号量、互斥量,或者在if条件中设置一个布尔值


您可能需要使用信号量或互斥来保护易受影响的数据不受异步写入的影响,但在这种情况下这不是问题。

我认为您可以使用线程而不是进程,初始化一些全局变量并在子线程中分配变量值。控制父线程中的输出。

我认为您可以使用线程而不是进程,初始化一些全局变量并在子线程中分配变量值。控制父线程中的输出。

快速脏方法:

        } else if (pids[i] == 0) { 
            usleep(i*1000);  /* wait 1ms for child 1, 2ms for child 2,... */
            if (i==0){
                    lineCount = countLines(argv[1]);
                    printf("This is child proccess %d, and the number of lines is %d\n", i+1, lineCount);
                    exit(0);
                }
                else if (i==1){ 
                    wordCount = countWords(argv[1]);
                    printf("This is child proccess %d, and the number of words is %d\n", i+1, wordCount);
                    exit(0);
                }
                else if (i==2){
                    charCount += countChars(argv[1]);
                    printf("This is child proccess %d, and the number of characters is %d\n", i+1, charCount);
                    exit(0);
                }
        } 

另一种方法是让父进程创建三个UNIX套接字,并使用
select()
或类似的方法侦听所有这些套接字。Childs将连接并写入套接字,退出,然后父进程将以正确的顺序打印收到的信息。

快速脏方法:

        } else if (pids[i] == 0) { 
            usleep(i*1000);  /* wait 1ms for child 1, 2ms for child 2,... */
            if (i==0){
                    lineCount = countLines(argv[1]);
                    printf("This is child proccess %d, and the number of lines is %d\n", i+1, lineCount);
                    exit(0);
                }
                else if (i==1){ 
                    wordCount = countWords(argv[1]);
                    printf("This is child proccess %d, and the number of words is %d\n", i+1, wordCount);
                    exit(0);
                }
                else if (i==2){
                    charCount += countChars(argv[1]);
                    printf("This is child proccess %d, and the number of characters is %d\n", i+1, charCount);
                    exit(0);
                }
        } 

另一种方法是让父进程创建三个UNIX套接字,并使用
select()
或类似的方法侦听所有这些套接字。Childs将连接并写入套接字,退出,然后父进程将以正确的顺序打印收到的信息。

我将尝试使用布尔标志,看看是否有帮助。谢谢您的建议。我是C语言的新手,所以我对信号量不是很熟悉。如果不使用共享内存,这些都不能工作。普通内存中的互斥、信号量、布尔值等仍将导致子内存中的副本不会反映在父内存或其他子内存中。您可以通过使用命名信号量或类似的东西并在子对象中打开它们来解决这个问题,但我严重怀疑这是本练习的重点。据我所知,共享内存是由操作系统实现的模型,而不是进程本身。这是不准确的吗?操作系统当然会实现它,但在这种情况下,流程会直接请求这些服务。我将尝试使用布尔标志,看看这是否有帮助。谢谢你的建议。我是C语言的新手,所以我对信号量不是很熟悉。如果不使用共享内存,这些都不能工作。普通内存中的互斥、信号量、布尔值等仍将导致子内存中的副本不会反映在父内存或其他子内存中。您可以通过使用命名信号量或类似的东西并在子对象中打开它们来解决这个问题,但我严重怀疑这是本练习的重点。据我所知,共享内存是由操作系统实现的模型,而不是进程本身。这是不准确的吗?操作系统当然会实现它,但在这种情况下,流程会直接请求这些服务。为什么您认为以不同的顺序提供这些服务是不可取的?尽快得到结果似乎是一个很好的好处。约翰:我对输出有一个要求,这就是为什么。我知道更快的结果更好:)哦,重新阅读你的需求,确保这是你真正应该做的。如果您运行多个子系统并让它们将结果通过管道传回给父系统,然后由父系统打印这些结果,这将是有意义的。同时运行3个孩子然后强制他们同步是没有意义的,特别是因为你说你不熟悉这样做所需的机制。您可以轻松地在循环中的下一个子循环之后运行一个子循环,并以更少的工作获得相同的结果。为什么您认为不希望将它们按不同的顺序排列?尽快得到结果似乎是一个很好的好处。约翰:我对输出有一个要求,这就是为什么。我知道更快的结果更好:)哦,重新阅读你的需求,确保这是你真正应该做的。如果您运行多个子系统并让它们将结果通过管道传回给父系统,然后由父系统打印这些结果,这将是有意义的。同时运行3个孩子然后强制他们同步是没有意义的,特别是因为你说你不熟悉这样做所需的机制。你可以很容易地在循环中的下一个孩子之后运行一个孩子,并且用更少的工作获得相同的结果。谢谢,是的,我只是需要一些快速的东西。谢谢,是的,我只是需要一些快速的东西。