我一直在用这个递归函数来获取fork()
创建的子进程的总数。不过,我似乎无法正确处理。当我尝试使用WEXITSTATUS()
时,程序输出变得非常不稳定。有没有一种方法可以汇总此函数中产生的子进程总数?管道是这样做的唯一方法,还是有更简单的方法?
它将传递“。”,以在当前工作目录中启动该功能。它遍历该目录和所有子目录,并在找到子目录时进行分叉。 verifyFileType()
仅检查找到的文件是否为CSV。
**编辑后的功能更加清晰
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
int traverse(char* directory)
{
struct dirent *currentDir;
DIR *traverser = opendir(directory);
if (traverser == NULL)
{
printf("Error: Could not open directory.\n");
return 0;
}
while ((currentDir = readdir(traverser)) != NULL)
{
if (currentDir->d_type == DT_DIR && strcmp(currentDir->d_name, ".") != 0 && strcmp(currentDir->d_name, "..") != 0)
{
PID = fork();
if (PID == 0)
{
char pathBuffer[1024];
snprintf(pathBuffer, sizeof(pathBuffer), "%s/%s", directory, currentDir->d_name);
traverse(pathBuffer);
//int childProc = traverse(pathBuffer);
//return childProc + 1;
exit(0);
}
else
{
//do parent stuff?
}
}
else if (strcmp(currentDir->d_name, ".") != 0 && strcmp(currentDir->d_name, "..") != 0)
{
if (verifyFileType(currentDir->d_name) == 0)
{
//if directory = '.', only send file name as fopen() arg
printf("%s%s\n", directory, currentDir->d_name);
}
}
}
if (PID > 0)
{
int status = 0;
wait(&status);
//int returned = WEXITSTATUS(status);
//return returned + 1;
}
else if (PID == -1)
{
printf("Error waiting on children. Aborting.\n");
_exit(0);
}
closedir(traverser);
return 0;
}
int main (int argc, char **argv)
{
char* beginningDir = ".";
rootPID = getpid();
/*
int procCount = 0;
procCount = traverse(beginningDir);
printf("Proc Count: %d\n", procCount);
*/
traverse(beginningDir);
return 0;
}
答案 0 :(得分:1)
我认为您只能使用外部实体来实现这一点,因为分叉的流程没有什么共同点(父母除外)。
让我们使用一个文件。我们可以使用tmpfile()
获取文件。我们需要使用flock(fileno(FILE *), ...)
进行一些锁定。每个孩子都会将一个字节写入临时文件。运行完所有子项后,我可以得到文件的大小-这样我将得到子项数:
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/wait.h>
#include <stdbool.h>
#include <sys/file.h>
#include <sys/types.h>
#include <unistd.h>
typedef FILE cnt_t;
/**
* Create interprocess counter.
* Should be created once (and only once) by the parent process.
*/
cnt_t *cnt_new(void)
{
return tmpfile();
}
/**
* Remove interprocess counter.
* Should be called by all childs and parent
*/
void cnt_delete(cnt_t *t)
{
fclose(t);
}
void _cnt_lock(cnt_t *t)
{
for (int ret; (ret = flock(fileno(t), LOCK_EX)) != 0;) {
assert(ret == EWOULDBLOCK);
}
}
void _cnt_unlock(cnt_t *t)
{
if (flock(fileno(t), LOCK_UN) != 0) {
assert(0);
}
}
/**
* Increments counter by 1.
*/
void cnt_inc(cnt_t *t) {
assert(t != NULL);
_cnt_lock(t);
if (fwrite((char[1]){'X'}, sizeof(char), 1, t) < 0) {
assert(0);
}
if (fflush(t) != 0) {
assert(0);
}
_cnt_unlock(t);
}
void cnt_println(cnt_t *t)
{
_cnt_lock(t);
if (fseek(t, 0L, SEEK_SET) < 0) {
assert(0);
}
char buf[124];
size_t cnt = fread(buf, sizeof(char), 124, t);
printf("cnt(%p) = %ld '%.*s'\n", cnt, (void*)t, cnt, buf);
_cnt_unlock(t);
}
/**
* Get's counter value.
*/
long cnt_getCount(cnt_t *t)
{
assert(t != NULL);
_cnt_lock(t);
if (fseek(t, 0L, SEEK_END) < 0) {
assert(0);
}
const long sz = ftell(t);
if (sz < 0) {
assert(0);
}
_cnt_unlock(t);
return sz;
}
/* ----------------------------------------------------------- */
int main()
{
srand(0);
cnt_t *cntobj = cnt_new();
bool child = false;
for (int i = 0; i < 5; ++i) {
const int ret = fork();
switch (ret) {
case 0:
cnt_inc(cntobj);
child = true;
break;
case -1:
fprintf(stderr, "fork error!\n");
exit(-1);
break;
default:
fprintf(stderr, "%d -> %d\n", getpid(), ret);
break;
}
}
while (wait(NULL) != -1) continue;
if (child) {
cnt_delete(cntobj);
exit(0);
}
const long cnt = cnt_getCount(cntobj);
cnt_delete(cntobj);
fprintf(stderr, "childs %ld\n", cnt);
return 0;
}
也许我在混淆方面做得太多了(typedef FILE cnt_t
看起来很奇怪),但是代码可以正常工作并返回正确的数字31。在线版本可以在jdoodle获得。
这是仅使用管道的解决方案:
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/wait.h>
#include <stdbool.h>
#include <sys/file.h>
#include <sys/types.h>
#include <unistd.h>
typedef struct {
int p[2];
} cnt_t;
/**
* Create interprocess counter.
* Should be created once (and only once) by the parent process.
*/
cnt_t *cnt_new(void)
{
cnt_t *t = malloc(sizeof(*t));
assert(t != NULL);
if (pipe(t->p) < 0) {
assert(0);
}
if (fcntl(t->p[0], F_SETFL, O_NONBLOCK) < 0) {
assert(0);
}
return t;
}
/**
* Remove interprocess counter.
* Should be called by all childs and parent
*/
void cnt_delete(cnt_t *t)
{
close(t->p[0]);
close(t->p[1]);
t->p[0] = 0;
t->p[1] = 0;
free(t);
}
/**
* Increments counter by 1.
*/
void cnt_inc(cnt_t *t)
{
assert(t != NULL);
if (write(t->p[1], (char[1]){'X'}, 1 * sizeof(char)) < 0) {
assert(0);
}
}
/**
* Get's counter value.
*/
long cnt_getCount(cnt_t *t)
{
assert(t != NULL);
char c;
long cnt = 0;
ssize_t tmp;
errno = 0;
while ((tmp = read(t->p[0], &c, 1)) == 1) {
++cnt;
}
if (tmp < 0 && errno != EWOULDBLOCK) {
assert(0);
}
const long ret = cnt;
while (cnt--) {
if (write(t->p[1], (char[1]){'X'}, 1) < 0) {
assert(0);
}
}
return ret;
}
/* ----------------------------------------------------------- */
int main()
{
srand(0);
cnt_t *cntobj = cnt_new();
bool child = false;
for (int i = 0; i < 5; ++i) {
const int ret = fork();
switch (ret) {
case 0:
cnt_inc(cntobj);
child = true;
break;
case -1:
fprintf(stderr, "fork error!\n");
exit(-1);
break;
default:
fprintf(stderr, "%d -> %d\n", getpid(), ret);
break;
}
}
while (wait(NULL) != -1) continue;
if (child) {
cnt_delete(cntobj);
exit(0);
}
const long cnt = cnt_getCount(cntobj);
cnt_delete(cntobj);
fprintf(stderr, "childs %ld\n", cnt);
return 0;
}
效果一样好,可能更快。实时版本仍为jdoodle。
这些示例使用了assert
进行的愚蠢错误处理,它们仅用于显示该方法并且该方法有效。
也许我们还可以使用posix shemaphores和一些进程间通信,一些shmget
和semop
以及例如排队的sempahore计数来创建解决方案。
答案 1 :(得分:0)
您可以尝试一下, 这确实很接近您所做的事情,但是我只计算出我产生的孩子数量,然后等待他们。
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <unistd.h>
int traverse(char* directory) {
struct dirent *currentDir;
DIR *traverser = opendir(directory);
if (traverser == NULL) {
printf("Error: Could not open directory.\n");
return 0;
}
size_t nb_child = 0;
while ((currentDir = readdir(traverser)) != NULL)
{
if (strcmp(currentDir->d_name, ".") == 0
|| strcmp(currentDir->d_name, "..") == 0)
continue; // ignore . and ..
// if subdirectory => fork to explore
if (currentDir->d_type == DT_DIR) {
pid_t PID = fork();
if (PID == 0) {
char pathBuffer[1024];
snprintf(pathBuffer, sizeof(pathBuffer), "%s/%s",
directory, currentDir->d_name);
return traverse(pathBuffer);
} else {
nb_child++; // keep track of the nomber of children
}
} else { // non directory "file"
// Do you verify here
printf("%s%s\n", directory, currentDir->d_name);
}
}
// loop until we waited for all children
for (size_t i = 0; i < nb_child; i++)
wait(NULL);
closedir(traverser);
return 0;
}
int main() {
return traverse(argv[1]);
}
答案 2 :(得分:0)
您在每个进程中产生了许多子目录,这些子目录对应于子目录的数目,但您不必等待所有子目录。
您只等待最后一个孩子。
您需要将所有PID都存储在数组中,然后在循环中等待它们。然后对所有WEXITSTATUS
进行求和,然后返回该值(在为您自己添加一个值之后)。