프로세스 간에는 공유되는 부분이 없기에 별도의 방법이 필요하다
• 파이프
부모, 자식 프로세스 간의 통신을 위해서 사용한다
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
int pfd[2];
pipe(pfd); // pfd[0] - read, pfd[1] - write 하는 파이프
printf("%d, %d\n", pfd[0], pfd[1]);
char buf[] = "hello parent";
char buf2[1024];
int n;
switch (fork())
{
case -1:
perror("fork error");
exit(1);
break;
case 0:
//자식 프로세스에서 쓰기 작업만 하기 위해서 read 디스크립터 닫기
close(pfd[0]);
// 1번 읽기 파일 디스크립터가 pfd[1]을 가리키게 하기
dup2(pfd[1],1);
close(pfd[1]);
// write(1, buf, strlen(buf));
execlp("ps", "ps", NULL);
perror("execlp");
exit(1);
break;
default:
close(pfd[1]);
dup2(pfd[0],0);
execlp("wc", "wc", "-l", NULL);
// n = read(0, buf2, sizeof(buf2));
// buf2[n] == '\0';
// printf("%s\n", buf2);
wait(NULL);
break;
}
}
-- pipe() 메서드를 이용해서 배쉬 쉘에서 파이프 연산이 가능하게 하는 코드
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <fcntl.h>
void redirect_out(char **arglist)
{
int fd, i;
for (int i = 0; arglist[i] != NULL; i++)
{
// 리다이렉트 기호가 있음
if (strcmp(arglist[i], ">") == 0)
{
fd = open(arglist[i + 1], O_WRONLY | O_TRUNC | O_CREAT, 644);
if (fd == -1)
{
perror("open");
return;
}
// dup 쓰는방법
// close(1);
// dup(fd);
dup2(fd, 1);
close(fd);
arglist[i] = NULL;
}
}
}
int pipe_check(char **arglist)
{
for (int i = 0; arglist[i] != NULL; i++)
{
if (strcmp(arglist[i], "|") == 0)
{
return i;
}
}
return 0;
}
int is_background(char **arglist)
{
int i = 0;
for (i = 0; arglist[i] != NULL; i++)
;
// 마지막 인자가 &인 백그라운드 요청이면
if (strcmp(arglist[i - 1], "&") == 0)
{
// execvp 메서드에 &가 전달되면 안됨
arglist[i - 1] = NULL;
return 1;
}
else
return 0;
}
void run_command(char **arglist)
{
pid_t cpid;
int back_flag = 0;
int pipe_pos = 0;
if (is_background(arglist))
{
back_flag = 1;
}
if ((pipe_pos = pipe_check(arglist)) > 0)
{
int pfd[2];
pipe(pfd);
arglist[pipe_pos] = NULL;
switch (cpid = fork())
{
case -1:
break;
case 0:
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
//파이프
close(pfd[0]);
dup2(pfd[1],1);
close(pfd[1]);
//ls -l | grep bash
redirect_out(arglist);
execvp(arglist[0], arglist);
perror("execvp");
exit(1);
break;
default:
// if (back_flag == 0) waitpid(cpid, NULL, 0);
close(pfd[1]);
dup2(pfd[0],0);
close(pfd[0]);
execvp(arglist[pipe_pos+1],&arglist[pipe_pos+1]);
perror("execvp");
exit(1);
break;
}
}
else
{
switch (cpid = fork())
{
case -1:
break;
case 0:
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
redirect_out(arglist);
execvp(arglist[0], arglist);
perror("execvp");
exit(1);
break;
default:
if (back_flag == 0) waitpid(cpid, NULL, 0);
break;
}
}
}
• 메세지 큐
멀티 프로세스에서 양방향 통신
메세지를 타입으로 구분해서 선택적으로 수신한다
-- 송신자가 수신자에게 메세지 하나만 보내는 예제
- 수신자
#include <stdio.h>
#include <unistd.h>
#include <sys/msg.h>
#define MSQKEY 51234
struct msgbuf {
long mtype; /* 메시지의 타입 : 0 이상의 정숫값 */
char mtext[BUFSIZ]; /* 메시지의 내용 : 1바이트 이상의 문자열 */
};
int main(int argc, char **argv)
{
key_t key;
int n, msqid;
struct msgbuf mb;
key = MSQKEY;
/* 메시지 큐의 채널을 생성한다. */
if((msqid = msgget(key, IPC_CREAT | 0666)) < 0) {
perror("msgget()");
return -1;
}
/* 메시지 큐에서 데이터를 가져온다. */
while((n = msgrcv(msqid, &mb, sizeof(mb), 0, 0)) > 0) {
switch (mb.mtype) {
/* 메시지 타입(mtype)이 1이면 화면에 가져온 데이터를 출력한다. */
case 1:
mb.mtext[n]='\0';
write(1, mb.mtext, n);
break;
/* 메시지 타입(mtype)이 2이면 메시지 큐의 채널을 삭제한다. */
case 2:
if(msgctl(msqid, IPC_RMID, (struct msqid_ds *) 0) == -1) {
perror("msgctl()");
return -1;
}
break;
}
}
msgctl(msqid, IPC_RMID, (struct msqid_ds *) 0) ;
return 0;
}
- 송신자
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/msg.h>
#define MSQKEY 51234
struct msgbuf {
long mtype;
char mtext[BUFSIZ];
};
int main(int argc, char **argv)
{
key_t key;
int rc, msqid;
char* msg_text = "hello world\n";
struct msgbuf *mb;
mb = (struct msgbuf*)malloc(sizeof(struct msgbuf) + strlen(msg_text));
key = MSQKEY;
if((msqid = msgget(key, IPC_CREAT|0666)) < 0) { /* 메시지 큐의 채널을 가져온다. */
perror("msgget()");
return -1;
}
/* mtype을 1로 설정하고 hello world라는 문자열을 보낸다. */
mb->mtype = 1;
strcpy(mb->mtext, msg_text);
rc = msgsnd(msqid, mb, sizeof(msg_text)+1, 0); /* 메시지 큐로 데이터를 보낸다. */
//rc = msgsnd(msqid, mb, sizeof(struct msgbuf), 0); /* 메시지 큐로 데이터를 보낸다. */
if(rc == -1) {
perror("msgsnd()");
return -1;
}
/* mtype을 2로 설정하고 보낸다. */
mb->mtype = 2;
memset(mb->mtext, 0, strlen(mb->mtext));
if(msgsnd(msqid, mb, strlen(mb->mtext), 0) < 0) {
perror("msgsnd()");
return -1;
}
}
• 공유 메모리
프로세스들이 메모리를 공유하면서 사용하는 방식
송신
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main()
{
int shmid, i,j ;
char *shmaddr;
if((shmid=shmget(0x123400, 30, 0660|IPC_CREAT|IPC_EXCL))==-1) {
if((shmid=shmget(0x123400, 30, 0660))==-1){
perror("shmget");
exit(1);
}
}
if((shmaddr=shmat(shmid, (char *)0, 0))== (char *)-1) {
perror("shmat");
exit(1);
}
for(i=0; i<20; i++) {
sprintf(shmaddr, "shared memory test %d", i+1);
printf("send : %s\n", shmaddr);
for(j=0; j<500000000; j++);
}
sprintf(shmaddr, "end");
if(shmdt(shmaddr)==-1 ) {
perror("shmdt");
exit(1);
}
return 0;
}
수신
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main()
{
int shmid, i, j;
char *shmaddr;
if((shmid=shmget(0x123400, 30, 0660|IPC_CREAT|IPC_EXCL))==-1) {
if((shmid=shmget(0x123400, 30, 0660))==-1){
perror("shmget");
exit(1);
}
}
if((shmaddr= shmat(shmid, (char *)0, 0))== (char *)-1) {
perror("shmat");
exit(1);
}
while(1) {
if(!strcmp(shmaddr,"end"))
break;
if(!strcmp(shmaddr,""))
continue;
printf("recv : %s\n", shmaddr);
for(j=0; j<499999999; j++);
}
if(shmdt(shmaddr) == -1 ) {
perror("shmdt");
exit(1);
}
if(shmctl(shmid, IPC_RMID, (struct shmid_ds *)0) == -1 ) {
perror("shmctl");
exit(1);
}
return 0;
}
• 세마포어
P, V 연산
p연산은 임계구역 전에 세마포 변수를 감소키기고
v 연산은 임계구역에서 작업이 이루어진 후 세마포 변수를 증가시킨다
'대외활동 > 시스템프로그래밍' 카테고리의 다른 글
tcp 채팅 프로그램 (0) | 2024.09.13 |
---|---|
0906 웹서버 부팅시 실행 (0) | 2024.09.06 |
0828 프로세스, 블로킹/논블로킹 (6) | 2024.08.28 |
0827 파일락, 링크, stat, 디렉토리, 시간, 프로세스, 시그널 (0) | 2024.08.27 |
라즈베리파이 크로스컴파일 설정 (0) | 2024.08.26 |