gpt4 book ai didi

c - 如何从此递归函数中获取 fork() 调用的子进程总数?

转载 作者:太空宇宙 更新时间:2023-11-03 23:38:27 25 4
gpt4 key购买 nike

我一直在弄乱这个递归函数,试图获取 fork() 创建的子进程总数。不过,我似乎做对了。当我尝试使用 WEXITSTATUS() 时,程序输出变得非常不稳定。有没有办法求和这个函数中产生的子进程总数?管道是做到这一点的唯一方法,还是有更简单的方法?

它被传递“.”,以在当前工作目录中启动函数。它遍历该目录和所有子目录,只要找到子目录就 fork 。 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;
}

最佳答案

我认为你只能使用外部实体来实现,因为 fork 进程没有任何共同点(父进程除外)。
让我们使用一个文件。我们可以使用 tmpfile() 获取文件。我们需要一些锁定,使用 flock(fileno(FILE *), ...)。每个 child 都会将一个字节写入临时文件。在所有 child 都运行后,我可以获得文件的大小 - 因此我将获得 child 的数量:

#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 信号量和一些进程间通信、一些 shmgetsemop 以及例如排队信号量计数来创建解决方案。

关于c - 如何从此递归函数中获取 fork() 调用的子进程总数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52955586/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com