第十五章 进程间通信:
#include <unistd.h>
int pipe(int filedes[2]);
if success return 0, else error return -1
#include <stdio.h>
FILE * popen(const char * cmdstring, const char * type);
int pclose(FILE * fp);
if success return exit-status, else error return -1
#include <sys/stat.h>
int mkfifo(const char * pathname, mode_t mode);
after mkfifo, we can open/read/write/close/unlink it
if success return 0, else error return -1
#include <sys/ipc.h>
key_t ftok(const char * path, int id);
if error return (key_t)-1
#include <sys/msg.h>
int msgget(key_t key, int flag);
if success return msg-id, else error return -1
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds * buf);
cmd:
IPC_STAT, IPC_SET, IPC_RMID
if success return 0, else error return -1
#include <sys/msg.h>
int msgsnd(int msqid, const void * ptr, size_t nbytes, int flag);
if success return 0, else error return -1
#include <sys/msg.h>
ssize_t msgrcv(int msqid, void * ptr, size_t nbytes, long type, int flag);
if success return msg-data-length, else error return -1
#include <sys/sem.h>
int semget(key_t key, int nsems, int flag);
if success return 0, else error return -1
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, ... /* union semun arg */ );
cmd:
IPC_STAT, IPC_SET, IPC_RMID,
GETVAL, SETVAL, GETPID,
GETNCNT, GETZCNT, GETALL, SETALL
union semun {
int val; /* for SETVAL */
struct semid_ds * buf; /* for IPC_STAT and IPC_SET */
unsigned short * array; /* for GETALL and SETALL */
};
#include <sys/sem.h>
int semop(int semid, struct sembuf semoparray[], size_t nops);
if success return 0, else error return -1
struct sembuf {
unsigned short sem_num; /* member # in set (0, 1, ..., nsems-1) */
short sem_op; /* operation (negative, 0, or positive) */
short sem_flg; /* IPC_NOWAIT, SEM_UNDO */
};
if sem_op > 0 free source, else if sem_op < 0 get source
#include <sys/shm.h>
int shmget(key_t key, size_t size, int flag);
if success return shared-id, else error return -1
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds * buf);
cmd:
IPC_STAT, IPC_SET, IPC_RMID,
SHM_LOCK, SHM_UNLOCK /* only for Linux and Solaris */
if success return 0, else error return -1
#include <sys/shm.h>
void * shmat(int shmid, const void * addr, int flag);
if error return (void *)-1
#include <sys/shm.h>
int shmdt(void * addr);
if success return 0, else error return -1
示例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define MAXLINE 1024
int
main(void)
{
int n;
int int1;
int int2;
char line[MAXLINE];
while ((n = read(STDIN_FILENO, line, MAXLINE)) > 0) {
line[n] = '\0'; /* null terminate */
if (sscanf(line, "%d%d", &int1, &int2) == 2) {
sprintf(line, "%d\n", int1 + int2);
n = strlen(line);
if (write(STDOUT_FILENO, line, n) != n) {
printf("write error\n");
exit(1);
}
}
else {
if (write(STDOUT_FILENO, "invalid args\n", 13) != 13) {
printf("write error\n");
exit(1);
}
}
}
exit(0);
}
#include <stdio.h>
#include <stdlib.h>
#define MAXLINE 1024
int
main(void)
{
int int1;
int int2;
char line[MAXLINE];
if (setvbuf(stdin, NULL, _IOLBF, 0) != 0) { /* pipe is _IOFBF */
printf("setvbuf error\n");
exit(1);
}
if (setvbuf(stdout, NULL, _IOLBF, 0) != 0) { /* pipe is _IOFBF */
printf("setvbuf error\n");
exit(1);
}
while (fgets(line, MAXLINE, stdin) != NULL) {
if (sscanf(line, "%d%d", &int1, &int2) == 2) {
if (printf("%d\n", int1 + int2) == EOF) {
printf("printf error\n");
exit(1);
}
}
else {
if (printf("invalid args\n") == EOF) {
printf("printf error\n");
exit(1);
}
}
}
exit(0);
}
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
int
main(void)
{
int c;
while ((c = getchar()) != EOF) {
if (isupper(c)) {
c = tolower(c);
}
if (putchar(c) == EOF) {
printf("output error\n");
exit(1);
}
if (c == '\n') {
fflush(stdout);
}
}
exit(0);
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static int pfd1[2];
static int pfd2[2];
void
TELL_WAIT(void)
{
if (pipe(pfd1) < 0 || pipe(pfd2) < 0) {
printf("pipe error\n");
exit(1);
}
}
void
TELL_PARENT(pid_t pid)
{
if (write(pfd2[1], "c", 1) != 1) {
printf("write error\n");
exit(1);
}
}
void
WAIT_PARENT(void)
{
char c;
if (read(pfd1[0], &c, 1) != 1) {
printf("read error\n");
exit(1);
}
if (c != 'p') {
printf("WAIT_PARENT: incorrent data\n");
exit(1);
}
}
void
TELL_CHILD(pid_t pid)
{
if (write(pfd1[1], "p", 1) != 1) {
printf("write error\n");
exit(1);
}
}
void
WAIT_CHILD(void)
{
char c;
if (read(pfd2[0], &c, 1) != 1) {
printf("read error\n");
exit(1);
}
if (c != 'c') {
printf("WAIT_CHILD: incorrect data\n");
exit(1);
}
}
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#define MAXLINE 1024
int
main(void)
{
int n;
int fd[2];
pid_t pid;
char line[MAXLINE];
if (pipe(fd) < 0) {
printf("pipe error\n");
exit(1);
}
if ((pid = fork()) < 0) {
printf("fork error\n");
exit(1);
}
else if (pid > 0) {
close(fd[0]);
write(fd[1], "hello world\n", 12);
}
else {
close(fd[1]);
n = read(fd[0], line, MAXLINE);
write(STDOUT_FILENO, line, n);
}
exit(0);
}
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define MAXLINE 1024
#define DEF_PAGER "/bin/more" /* default pager program */
int
main(int argc, char * argv[])
{
int n;
int fd[2];
pid_t pid;
char * pager;
char * argv0;
char line[MAXLINE];
FILE * fp;
if (argc != 2) {
printf("usage: %s <pathname>\n", argv[0]);
exit(1);
}
if ((fp = fopen(argv[1], "r")) == NULL) {
printf("cannot open %s\n", argv[1]);
exit(1);
}
if (pipe(fd) < 0) {
printf("pipe error\n");
exit(1);
}
if ((pid = fork()) < 0) {
printf("fork error\n");
exit(1);
}
else if (pid > 0) {
close(fd[0]); /* close read end */
/* parent copies argv[1] to pipe */
while (fgets(line, MAXLINE, fp) != NULL) {
n = strlen(line);
if (write(fd[1], line, n) != n) {
printf("write error\n");
exit(1);
}
}
if (ferror(fp)) {
printf("fgets error\n");
exit(1);
}
close(fd[1]); /* close write end of pipe for reader */
if (waitpid(pid, NULL, 0) < 0) {
printf("waitpid error\n");
exit(1);
}
exit(0);
}
else {
close(fd[1]); /* close write end */
if (fd[0] != STDIN_FILENO) {
if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) {
printf("dup2 error to stdin\n");
exit(1);
}
close(fd[0]); /* donnot need this after dup2 */
}
/* get arguments for execl() */
if ((pager = getenv("PAGER")) == NULL) {
pager = DEF_PAGER;
}
if ((argv0 = strrchr(pager, '/')) != NULL) {
++argv0; /* step past rightmost slash */
}
else {
argv0 = pager; /* no slash in pager */
}
if (execl(pager, argv0, (char *)0) < 0) {
printf("execl error for %s\n", pager);
}
}
exit(0);
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#define MAXLINE 1024
#define PAGER "${PAGER:-more}" /* environment variable, or default */
int
main(int argc, char * argv[])
{
char line[MAXLINE];
FILE * fpin;
FILE * fpout;
if (argc != 2) {
printf("usage: %s <pathname>\n", argv[0]);
exit(1);
}
if ((fpin = fopen(argv[1], "r")) == NULL) {
printf("cannot open %s\n", argv[1]);
exit(1);
}
if ((fpout = popen(PAGER, "w")) == NULL) {
printf("popen error\n");
exit(1);
}
/* copy argv[1] to pager */
while (fgets(line, MAXLINE, fpin) != NULL) {
if (fputs(line, fpout) == EOF) {
printf("fputs error to pipe\n");
exit(1);
}
}
if (ferror(fpin)) {
printf("fgets error\n");
exit(1);
}
if (pclose(fpout) == -1) {
printf("pclose error\n");
exit(1);
}
exit(0);
}
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
/*
* pointer to array allocated at run-time
*/
pid_t * childpid = NULL;
/*
* from our open_max()
*/
int maxfd;
FILE *
popen(const char * cmdstring, const char * type)
{
int i;
int pfd[2];
pid_t pid;
FILE * fp;
/* only allow "r" or "w" */
if ((type[0] != 'r' && type[0] != 'w') || type[1] != '\0') {
errno = EINVAL; /* required by POSIX */
return(NULL);
}
if (childpid == NULL) { /* first time through */
/* allocate zeroed out array for child pids */
maxfd = open_max();
if ((childpid = calloc(maxfd, sizeof(pid_t))) == NULL) {
return(NULL);
}
}
if (pipe(pfd) < 0) {
return(NULL); /* error set by pipe() */
}
if ((pid = fork()) < 0) {
return(NULL); /* error set by fork() */
}
else if (pid == 0) {
if (*type == 'r') {
close(pfd[0]);
if (pfd[1] != STDOUT_FILENO) {
dup2(pfd[1], STDOUT_FILENO);
close(pfd[1]);
}
}
else {
close(pfd[1]);
if (pfd[0] != STDIN_FILENO) {
dup2(pfd[0], STDIN_FILENO);
close(pfd[0]);
}
}
/* close all descriptors in childpid[] */
for (i = 0; i < maxfd; ++i) {
if (childpid[i] > 0) {
close(i);
}
}
execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
_exit(127);
}
/* parent continues */
if (*type == 'r') {
close(pfd[1]);
if ((fp = fdopen(pfd[0], type)) == NULL) {
return(NULL);
}
}
else {
close(pfd[0]);
if ((fp = fdopen(pfd[1], type)) == NULL) {
return(NULL);
}
}
childpid[fileno(fp)] = pid; /* remember child pid for this fd */
return(fp);
}
int
pclose(FILE * fp)
{
int fd;
int stat;
pid_t pid;
if (childpid == NULL) {
errno = EINVAL;
return(-1); /* popen() has never been called */
}
fd = fileno(fp);
if ((pid = childpid[fd]) == 0) {
errno = EINVAL;
return(-1); /* fp was not opened by popen() */
}
childpid[fd] = 0;
if (fclose(fp) == EOF) {
return(-1);
}
while (waitpid(pid, &stat, 0) < 0) {
if (errno != EINTR) {
return(-1); /* error other than EINTR from waitpid() */
}
}
return(stat); /* return child's termination status */
}
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#define MAXLINE 1024
int
main(void)
{
char line[MAXLINE];
FILE * fpin;
if ((fpin = popen("./tolower", "r")) == NULL) {
printf("popen error\n");
exit(0);
}
for (;;) {
fputs("prompt> ", stdout);
fflush(stdout);
if (fgets(line, MAXLINE, fpin) == NULL) { /* read from pipe */
break;
}
if (fputs(line, stdout) == EOF) {
printf("fputs error to pipe\n");
exit(1);
}
}
if (pclose(fpin) == -1) {
printf("pclose error\n");
exit(1);
}
putchar('\n');
exit(0);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#define MAXLINE 1024
void
sig_pipe(int signo)
{
printf("SIGPIPE caught\n");
exit(1);
}
int
main(void)
{
int n;
int fd1[2];
int fd2[2];
pid_t pid;
char line[MAXLINE];
if (signal(SIGPIPE, sig_pipe) == SIG_ERR) {
printf("signal error\n");
exit(0);
}
if (pipe(fd1) < 0 || pipe(fd2) < 0) {
printf("pipe error\n");
exit(0);
}
if ((pid = fork()) < 0) {
printf("fork error\n");
exit(0);
}
else if (pid > 0) {
close(fd1[0]);
close(fd2[1]);
while (fgets(line, MAXLINE, stdin) != NULL) {
n = strlen(line);
if (write(fd1[1], line, n) != n) {
printf("write error to pipe\n");
exit(1);
}
if ((n = read(fd2[0], line, MAXLINE)) < 0) {
printf("read error from pipe\n");
exit(1);
}
else if (n == 0) {
printf("child closed pipe\n");
break;
}
line[n] = '\0'; /* null terminate */
if (fputs(line, stdout) == EOF) {
printf("fputs error\n");
exit(1);
}
}
if (ferror(stdin)) {
printf("fgets error on stdin");
exit(1);
}
exit(0);
}
else {
close(fd1[1]);
close(fd2[0]);
if (fd1[0] != STDIN_FILENO) {
if (dup2(fd1[0], STDIN_FILENO) != STDIN_FILENO) {
printf("dup2 error to stdin\n");
exit(1);
}
close(fd1[0]);
}
if (fd2[1] != STDOUT_FILENO) {
if (dup2(fd2[1], STDOUT_FILENO) != STDOUT_FILENO) {
printf("dup2 error to stdin\n");
exit(1);
}
close(fd2[1]);
}
if (execl("./add", "add", (char *)0) < 0) {
printf("execl error\n");
exit(1);
}
}
exit(0);
}
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include "changefileflag.h"
#define FIFO "temp.fifo"
int
main(void)
{
int fdread;
int fdwrite;
unlink(FIFO);
if (mkfifo(FIFO, 0622) < 0) {
printf("mkfifo error\n");
exit(1);
}
if ((fdread = open(FIFO, O_RDONLY | O_NONBLOCK)) < 0) {
printf("open error for reading\n");
exit(1);
}
if ((fdwrite = open(FIFO, O_WRONLY)) < 0) {
printf("open error for writing\n");
exit(1);
}
clr_fl(fdread, O_NONBLOCK);
exit(0);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#define MAXLINE 1024
void
sig_pipe(int signo)
{
printf("SIGPIPE caught\n");
exit(1);
}
int
main(void)
{
int n;
int fd1[2];
int fd2[2];
pid_t pid;
char line[MAXLINE];
FILE * fpin;
FILE * fpout;
if (signal(SIGPIPE, sig_pipe) == SIG_ERR) {
printf("signal error\n");
exit(0);
}
if (pipe(fd1) < 0 || pipe(fd2) < 0) {
printf("pipe error\n");
exit(0);
}
if ((pid = fork()) < 0) {
printf("fork error\n");
exit(0);
}
else if (pid > 0) {
close(fd1[0]);
close(fd2[1]);
if ((fpin = fdopen(fd2[0], "r")) == NULL) {
printf("fdopen error\n");
exit(1);
}
if ((fpout = fdopen(fd1[1], "w")) == NULL) {
printf("fdopen error\n");
exit(1);
}
if (setvbuf(fpin, NULL, _IOLBF, 0) < 0) {
printf("setvbuf error\n");
exit(1);
}
if (setvbuf(fpout, NULL, _IOLBF, 0) < 0) {
printf("setvbuf error\n");
exit(1);
}
while (fgets(line, MAXLINE, stdin) != NULL) {
n = strlen(line);
if (fputs(line, fpout) == EOF) {
printf("write error to pipe\n");
exit(1);
}
if (fgets(line, MAXLINE, fpin) == NULL) {
printf("read error from pipe\n");
exit(1);
}
if (n == 0) {
printf("child closed pipe\n");
break;
}
line[n] = '\0'; /* null terminate */
if (fputs(line, stdout) == EOF) {
printf("fputs error\n");
exit(1);
}
}
if (ferror(stdin)) {
printf("fgets error on stdin");
exit(1);
}
exit(0);
}
else {
close(fd1[1]);
close(fd2[0]);
if (fd1[0] != STDIN_FILENO) {
if (dup2(fd1[0], STDIN_FILENO) != STDIN_FILENO) {
printf("dup2 error to stdin\n");
exit(1);
}
close(fd1[0]);
}
if (fd2[1] != STDOUT_FILENO) {
if (dup2(fd2[1], STDOUT_FILENO) != STDOUT_FILENO) {
printf("dup2 error to stdin\n");
exit(1);
}
close(fd2[1]);
}
if (execl("./add", "add", (char *)0) < 0) {
printf("execl error\n");
exit(1);
}
}
exit(0);
}
#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
#define ARRAY_SIZE 40000
#define MALLOC_SIZE 100000
#define SHM_SIZE 100000
#define SHM_MODE 0600 /* user read/write */
char array[ARRAY_SIZE]; /* uninitialized data = bss */
int
main(void)
{
int shmid;
char * ptr;
char * shmptr;
printf("array[] from %lx to %lx\n", (unsigned long)&array[0],
(unsigned long)&array[ARRAY_SIZE]);
printf("stack around %lx\n", (unsigned long)&shmid);
if ((ptr = malloc(MALLOC_SIZE)) == NULL) {
printf("malloc error\n");
exit(1);
}
printf("malloced from %lx to %lx\n", (unsigned long)ptr,
(unsigned long)ptr+MALLOC_SIZE);
if ((shmid = shmget(IPC_PRIVATE, SHM_SIZE, SHM_MODE)) < 0) {
printf("shmget error\n");
exit(1);
}
if ((shmptr = shmat(shmid, 0, 0)) == (void *)-1) {
printf("shmat error\n");
exit(1);
}
printf("shared momory attached from %lx to %lx\n",
(unsigned long)shmptr, (unsigned long)shmptr+SHM_SIZE);
if (shmctl(shmid, IPC_RMID, 0) < 0) {
printf("shmctl error\n");
exit(1);
}
exit(0);
}
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/mman.h>
#include "waitfor.h"
#define NLOOPS 1000
#define SIZE sizeof(long) /* size of shared memory area */
int
updata(long * ptr)
{
return((*ptr)++);
}
int
main(void)
{
int fd;
int i;
int counter;
pid_t pid;
void * area;
if ((fd = open("/dev/zero", O_RDWR)) < 0) {
printf("open error\n");
exit(1);
}
if ((area = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
fd, 0)) == MAP_FAILED) { /* will init area with 0 */
printf("mmap error\n");
exit(1);
}
close(fd); /* can close /dev/zero now that it is mapped */
TELL_WAIT();
if ((pid = fork()) < 0) {
printf("fork error\n");
exit(1);
}
else if (pid > 0) {
for (i = 0; i < NLOOPS; i += 2) {
if ((counter = updata((long *)area)) != i) {
printf("parent: excepted %d, got %d\n", i, counter);
exit(1);
}
TELL_CHILD(pid);
WAIT_CHILD();
}
}
else {
for (i = 1; i < NLOOPS + 1; i += 2) {
WAIT_PARENT();
if ((counter = updata((long *)area)) != i) {
printf("child: excepted %d, got %d\n", i, counter);
exit(1);
}
TELL_PARENT(getppid());
}
}
exit(0);
}
#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
#include "waitfor.h"
#define NLOOPS 1000
#define SIZE sizeof(long) /* size of shared memory area */
#define SHM_MODE 0600
int
updata(long * ptr)
{
return((*ptr)++);
}
int
main(void)
{
int i;
int shmid;
int counter;
pid_t pid;
void * area;
if ((shmid = shmget(IPC_PRIVATE, SIZE, SHM_MODE)) < 0) {
printf("shmget error\n");
exit(1);
}
if ((area = shmat(shmid, 0, 0)) == (void *)-1) {
printf("shmat error\n");
exit(1);
}
TELL_WAIT();
if ((pid = fork()) < 0) {
printf("fork error\n");
exit(1);
}
else if (pid > 0) {
for (i = 0; i < NLOOPS; i += 2) {
if ((counter = updata((long *)area)) != i) {
printf("parent: excepted %d, got %d\n", i, counter);
exit(1);
}
TELL_CHILD(pid);
WAIT_CHILD();
}
if (waitpid(pid, NULL, 0) != pid) {
printf("waitpid error\n");
exit(1);
}
if (shmctl(shmid, IPC_RMID, 0) < 0) {
printf("shmctl error\n");
exit(1);
}
}
else {
for (i = 1; i < NLOOPS + 1; i += 2) {
WAIT_PARENT();
if ((counter = updata((long *)area)) != i) {
printf("child: excepted %d, got %d\n", i, counter);
exit(1);
}
TELL_PARENT(getppid());
}
}
exit(0);
}