- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
所以我有一个项目要做,但我完全被难住了。我花了十个小时,却一无所获。我并不是特别想要答案的代码,但是一些伪代码和正确方向的良好提示会有所帮助!!
它派生出许多进程,k - 一个命令行参数,通过管道连接 - 每个进程都连接到下一个进程,最后一个进程连接到第一个进程。进程号 k 将其消息发送到进程号 (k+1)%n。
进程 0 从 stdin
读取一行。然后它将它传输到进程 1。每个其他进程读取该行,将字符串的第一个字节递增 1,然后将该行中继到下一个进程。在进行中继时,它会打印一条状态消息(如下所示)。
当消息返回到进程 0 时,它也被输出到标准输出。当进程接收到 EOF
(来自管道,如果它不是 0 的进程,或者来自 stdin
,对于进程 0),它打印最终字符串。这将关闭所有管道。
预期的输出是:
$ ./ring 4
hello
process #0 (32768) sending message: hello
process #1 (32769) relaying message: iello
process #2 (32770) relaying message: jello
process #3 (32767) relaying message: kello
I hear kello
^C
$
到目前为止我写了什么:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define BUFFER_SIZE 80
#define READ_END 0
#define WRITE_END 1
int main(int argc, char *argv[])
{
char readmsg[BUFFER_SIZE], readmsg2[BUFFER_SIZE], final[BUFFER_SIZE];
int pid, process;
int parent_child[2], child_parent[2];
process = 0;
if (pipe(child_parent) == -1) {
fprintf(stderr, "Pipe failed");
return 1;
}
if (pipe(parent_child) == -1) {
fprintf(stderr, "Pipe failed");
return 1;
}
pid = fork();
if (pid < 0) {
fprintf(stderr, "Fork failed");
return 1;
} else if (pid > 0) {
/* PARENT */
read(0, &readmsg, BUFFER_SIZE);
printf("process #%d (%d) sending message: %s",
0, getpid(), readmsg);
write(parent_child[WRITE_END], &readmsg, BUFFER_SIZE);
close(parent_child[WRITE_END]);
} else {
/* CHILD */
read(parent_child[READ_END], &readmsg2, BUFFER_SIZE);
readmsg2[0] += 1;
printf("process #%d (%d) relaying message: %s",
1, getpid(), readmsg2);
process += 1;
write(child_parent[WRITE_END], &readmsg2, BUFFER_SIZE);
}
read(child_parent[READ_END], &final, BUFFER_SIZE);
printf("I hear %d %s", pid - getpid(), final);
return 0;
}
它当前所做的是从 stdin 中读取字符串,将其传递给第一个进程并打印进程 0(虽然实际上无法获取 0,只是打印 0),然后将字符串通过管道传输到进程 1,这会扭曲字节 1,然后再次写入管道,然后在管道外,读取字符串并输出扭曲的字符串。
$ ./ring
hello
process #0 (6677) sending message: hello
process #1 (6678) relaying message: iello
I hear -6678 iello
^C
$
我不知道从这里去哪里。提前谢谢你,任何事情都会有帮助!!
在一些帮助下,这就是我现在所拥有的:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define BUFFER_SIZE 80
#define READ_END 0
#define WRITE_END 1
int main(int argc, char **argv) {
char buf[BUFFER_SIZE];
int process, rings, pid, pid_n, pid_n1, pid_1, i;
int Pn[2]; //Pipe for process n -> 0
int Pn_1[2]; //Pipe for process n-1 -> n
int Pn_2[2]; //Pipe for process n-2 -> n-1
int P_0[2]; //Pipe for process 0 -> 1
process = 0;
if (argc == 2) {
rings = atoi(argv[1]);
} else {
fprintf(stderr, "Usage: %s n, where n is number of rings\n", argv[0]);
exit(EXIT_FAILURE);
}
if ((pid = fork()) < 0) {
fprintf(stderr, "Fork failed");
return 1;
} else if (pid == 0) {
if ((pid_n = fork()) < 0) {
fprintf(stderr, "Fork failed");
return 1;
} else if (pid_n == 0) {
/* CHILD */
close(Pn[WRITE_END]);
close(Pn_1[READ_END]);
} else {
/* PARENT */
close(Pn[READ_END]);
close(Pn_1[WRITE_END]);
}
for (i = 0; i < rings; i++) {
if ((pid_n1 = fork()) < 0) {
fprintf(stderr, "Fork failed");
return 1;
} else if (pid_n1 == 0) {
/* CHILD */
close(Pn_1[WRITE_END]);
close(Pn_2[READ_END]);
} else {
/* PARENT */
close(Pn_1[READ_END]);
close(Pn_2[WRITE_END]);
}
}
/* Not sure about these last ones */
if ((pid_1 = fork()) < 0) {
fprintf(stderr, "Fork failed");
return 1;
} else if (pid_1 == 0) {
/* CHILD */
close(P_n2[WRITE_END]);
close(P_0[READ_END]);
} else {
/* PARENT */
close(P_n2[READ_END]);
close(P_0[WRITE_END]);
}
} else {
/* PARENT */
read(0, &buf, BUFFER_SIZE);
buf[BUFFER_SIZE - 1] = '\0';
printf("process first # (%d) sending message: %s", getpid(), buf);
write(P_0[WRITE_END], &buf, BUFFER_SIZE);
read(Pn[READ_END], &buf, BUFFER_SIZE);
buf[BUFFER_SIZE - 1] = '\0';
printf("I hear %s", buf);
}
return 0;
}
最佳答案
这是我自己画的图,展示了流程是如何相互连接的:
p4
C5 <--------- C4
/ \
p5 / p3 \
/ \
o----> C0 ---->o C3
\ /
p0 \ p2 /
\ /
C1 ---------> C2
p1
Cn 代表进程; C0是父进程。 pn 代表管道;另外两行是标准输入和标准输出。每个 child 都有一项适合 child 的简单任务。父级有一个更复杂的任务,主要是确保关闭正确数量的文件描述符。事实上,close()
非常重要,以至于我创建了一个调试函数 fd_close()
,以有条件地报告正在关闭的文件描述符。当我在代码中出现愚蠢的错误时,我也会使用它。
err_*()
函数是我在大多数程序中使用的代码的简化版本。它们通过将大多数错误报告转换为单行语句而不是要求多行来使错误报告变得不那么繁重。 (这些函数通常在“stderr.c”和“stderr.h”中,但这些文件有 750 行代码和注释,而且更全面。生产代码有一个选项支持为每个消息加上 PID 前缀,这是对于像这样的多进程系统也很重要。)
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
enum { BUFFER_SIZE = 1024 };
typedef int Pipe[2];
static int debug = 0;
static void fd_close(int fd);
/* These functions normally declared in stderr.h */
static void err_setarg0(const char *argv0);
static void err_sysexit(char const *fmt, ...);
static void err_usage(char const *usestr);
static void err_remark(char const *fmt, ...);
static void be_childish(Pipe in, Pipe out)
{
/* Close irrelevant ends of relevant pipes */
fd_close(in[1]);
fd_close(out[0]);
char buffer[BUFFER_SIZE];
ssize_t nbytes;
while ((nbytes = read(in[0], buffer, sizeof(buffer))) > 0)
{
buffer[0]++;
if (write(out[1], buffer, nbytes) != nbytes)
err_sysexit("%d: failed to write to pipe", (int)getpid());
}
fd_close(in[0]);
fd_close(out[1]);
exit(0);
}
int main(int argc, char **argv)
{
err_setarg0(argv[0]);
int nkids;
if (argc != 2 || (nkids = atoi(argv[1])) <= 1 || nkids >= 10)
err_usage("n # for n in 2..9");
err_remark("Parent has PID %d\n", (int)getpid());
Pipe pipelist[nkids];
if (pipe(pipelist[0]) != 0)
err_sysexit("Failed to create pipe #%d", 0);
if (debug)
err_remark("p[0][0] = %d; p[0][1] = %d\n", pipelist[0][0], pipelist[0][1]);
for (int i = 1; i < nkids; i++)
{
pid_t pid;
if (pipe(pipelist[i]) != 0)
err_sysexit("Failed to create pipe #%d", i);
if (debug)
err_remark("p[%d][0] = %d; p[%d][1] = %d\n", i, pipelist[i][0], i, pipelist[i][1]);
if ((pid = fork()) < 0)
err_sysexit("Failed to create child #%d", i);
if (pid == 0)
{
/* Close irrelevant pipes */
for (int j = 0; j < i-1; j++)
{
fd_close(pipelist[j][0]);
fd_close(pipelist[j][1]);
}
be_childish(pipelist[i-1], pipelist[i]);
/* NOTREACHED */
}
err_remark("Child %d has PID %d\n", i, (int)pid);
}
/* Close irrelevant pipes */
for (int j = 1; j < nkids-1; j++)
{
fd_close(pipelist[j][0]);
fd_close(pipelist[j][1]);
}
/* Close irrelevant ends of relevant pipes */
fd_close(pipelist[0][0]);
fd_close(pipelist[nkids-1][1]);
int w_fd = pipelist[0][1];
int r_fd = pipelist[nkids-1][0];
/* Main loop */
char buffer[BUFFER_SIZE];
while (printf("Input: ") > 0 && fgets(buffer, sizeof(buffer), stdin) != 0)
{
int len = strlen(buffer);
if (write(w_fd, buffer, len) != len)
err_sysexit("Failed to write to children");
if (read(r_fd, buffer, len) != len)
err_sysexit("Failed to read from children");
printf("Output: %.*s", len, buffer);
}
fd_close(w_fd);
fd_close(r_fd);
putchar('\n');
int status;
int corpse;
while ((corpse = wait(&status)) > 0)
err_remark("%d exited with status 0x%.4X\n", corpse, status);
return 0;
}
static void fd_close(int fd)
{
if (debug)
err_remark("%d: close(%d)\n", (int)getpid(), fd);
if (close(fd) != 0)
err_sysexit("%d: Failed to close %d\n", (int)getpid(), fd);
}
/* Normally in stderr.c */
static const char *arg0 = "<undefined>";
static void err_setarg0(const char *argv0)
{
arg0 = argv0;
}
static void err_usage(char const *usestr)
{
fprintf(stderr, "Usage: %s %s\n", arg0, usestr);
exit(1);
}
static void err_vsyswarn(char const *fmt, va_list args)
{
int errnum = errno;
fprintf(stderr, "%s:%d: ", arg0, (int)getpid());
vfprintf(stderr, fmt, args);
if (errnum != 0)
fprintf(stderr, " (%d: %s)", errnum, strerror(errnum));
putc('\n', stderr);
}
static void err_sysexit(char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
err_vsyswarn(fmt, args);
va_end(args);
exit(1);
}
static void err_remark(char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
}
示例输出:
$ ./pipecircle 9
Parent has PID 34473
Child 1 has PID 34474
Child 2 has PID 34475
Child 3 has PID 34476
Child 4 has PID 34477
Child 5 has PID 34478
Child 6 has PID 34479
Child 7 has PID 34480
Child 8 has PID 34481
Input: Hello
Output: Pello
Input: Bye
Output: Jye
Input: ^D
34474 exited with status 0x0000
34477 exited with status 0x0000
34479 exited with status 0x0000
34476 exited with status 0x0000
34475 exited with status 0x0000
34478 exited with status 0x0000
34480 exited with status 0x0000
34481 exited with status 0x0000
$
关于c - c中的 fork 和管道过程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19825489/
有3个 repo : 有 OpenAI Baselines 存储库:https://github.com/openai/baselines . 我有它的 fork :https://github.co
我试图了解在调用 fork() 后复制文件描述符的含义及其对争用的可能影响。 在“Linux 编程接口(interface)”24.2.1 (p517) 中: When a fork() is per
我对 systemd 如何跟踪主进程存在后仍然存在的主进程的子进程感兴趣? 最佳答案 Systemd 为此使用了 cgroups。在启动任何使用服务文件定义的可执行文件之前,systemd 会创建一个
这是输出--- 家长:我的pid是4525 parent :我 parent 的 pid 是 3350 parent 开始- 4525 3350 fork 前 fork 前 child 4526 45
我之前 fork 了 jockm/vert.x 并向他发送了拉取请求。现在我想 fork vert-x/vert.x (jockm/vert.x 的上游)并向他们发送不同的拉取请求。但是,当我单击“F
我想控制从 Perl 脚本派生的进程的名称 a。理想情况下它会像这样: ./forker.pl | ... | | fork("forked.pl"); |\ | \ | `--------\ |
我知道 fork() 在更高级别上做什么。我想知道的是这个—— 一旦有 fork 调用,trap 指令就会跟随并且控制跳转以执行 fork “处理程序”。现在,这个创建子进程的处理程序如何通过创建另一
我正在研究操作系统测验,但我不知道输出什么 if(fork()) fork() 会产生。有人可以解释吗? 我不明白这一行: if(fork()) 编辑: 我所说的“输出”是指如果执行此代码,将
这个问题在这里已经有了答案: Why does this program print "forked!" 4 times? (6 个答案) 关闭 3 年前。 在 C 中,fork() 函数将为父进程
有什么方法可以区分程序中不同 fork() 函数创建的子进程。 global variable i; SIGCHLD handler function() { i--; } handle() {
我正在重新开发一个系统,该系统将通过 http 向多个供应商之一发送消息。原来是perl脚本,重新开发很可能也会用perl。 在旧系统中,同时运行多个 perl 脚本,每个供应商运行 5 个。当一条消
Git 的新手,仍然有点困惑。我在 github 上 fork 了一个项目,想将项目所有者最近对原始项目所做的一些更改引入/merge 到我的 fork 中。这可能吗?该项目是只读的,但基本上,我想让
根据维基百科(可能是错误的) When a fork() system call is issued, a copy of all the pages corresponding to the par
我需要帮助了解如何在 Go 中妖魔化进程。 package main import ( "fmt" "os" ) func start() { var procAttr os.Pro
我已经执行了这段代码。我知道消息的顺序是任意顺序的(因为我明确没有使用信号量)我的程序流程如何?为什么? 父级被执行,因此“baz”被打印一次。有人可以解释为什么不打印“bar”吗?为什么我得到“fo
这个问题已经有答案了: Why does this program print "forked!" 4 times? (6 个回答) 已关闭 5 年前。 我对 fork 进程有疑问。我有一个代码是 i
我在弄清楚如何使用在不同进程之间创建的列表时遇到了麻烦。我所拥有的是: FileList.h - 我创建的列表 #include "Node.h" typedef struct FileList {
好吧,所以我一直在 stackoverflow 上查找这个问题,并且肯定在谷歌上搜索了半个小时,但我得到的答案似乎与我真正想做的事情几乎没有任何关系,希望有人能提供帮助我在这方面,代码如下: int
我正在尝试了解 fork-join 的工作原理。 维基百科有以下合并排序示例,其中左半部分被 fork ,右半部分由当前线程处理。 mergesort(A, lo, hi): if lo t
下面的代码输出了一系列的过程,它到底做了什么: _PARENT_ / \ /
我是一名优秀的程序员,十分优秀!