# 11장 1122 강의 요약
중간고사 마지막 문제 풀이 [semaphore]
barrier
n개의 프로세스가 실행될때 barrier가 호출될때까지 기다렸다가 수행
병렬 프로그램, 분산 시스템에서 필요한 시스템
barrier라는 동기화 도구 -> signal handler를 사용하여 구현하라
각 프로그램은 pid를 모두 안다고 가정
도착하면 나 도착했다를 다른 사람들에게 알려야 한다
SIGUSR를 보내서 알려야 한다
도착한 시그널의 갯수가 n-1개가 안되면 계속 기다리는 ..
### sigtest.c
#include <stdio.h>
#include <signal.h>
int cnt =0;
int pnum;
int pids[10];
void my_sig_handler(int signum){
//printf(“signum = %d \n”, signum);
cnt ++;
//printf(“cnt = %d \n”, cnt);
}
void barrier(){
int i;
for (i=0; i<pnum -1; i++){
kill(pids[i], SIGUSR1);
}
// n개의 프로세스가 barrier를 호출
while (cnt<pnum-1){
pause();
}
cnt=0;
}
void work(int sec){
int i, j, k;
int sum = 0;
for (i =0; i<sec; i++){
for (j =0; j<500; j++){
for (k=0; k<1000000; k++){
sum++;
}
}
}
}
int main(){
int i, work_t;
printf("pid = %d \n", getpid());
signal (SIGUSR, my_sig_handler);
printf("Enter the numbe of processes : ");
scanf("%d", &pnum);
srand(time(NULL));
for (i =0; i<pnum-1 ;i++){
printf("Enter %d process id : ", i);
scanf("%d", &pids[i]);
}
while(1){
work_t = srand() % 10 +1;
printf("Working for %d secs ... \n", work_t);
work(work_t);
printf(" Done\n");
printf("");
barrier();
}
}
## IPC (Inter-Process Communication)
IPC: 두 프로세스 간의 통신하는 방법
일반적으로 두개의 프로세스 사이에 데이터를 주고 받는 두 가지 방법
- message 기반
: fifo처럼 메세지를 send, receive
박스에 메세지를 쓰면 읽는 사람이 receive해서 받음
- shared memory(공유 메모리) 기반
: 변수 (int x;)를 선언
메모리를 정하고 하나는 쓰고, 하나는 읽기
메세지 큐 방식 - 동기화됨
보낸 순서대로 읽으면 없어짐
p1이 send
p2가 receive
shm 방식 - 시간 순으로 출력함
컴퓨터가 꺼지지 않는 이상, 공유 메모리를 해지하지 않는 이상 os영역에 계속 있음
새로 쓰면 덮어써져서 제일 마지막에 쓴 값만 읽을 수 있음
ipcs 명령어
ipcs : 현재 실행 중인 ipc의 상태들을 보여줌. message queue, shared memory segment, semaphore array가 보임
ipcs -q : message queue만 보여줌
ipcs -m : shared memory를 볼 수 있음
ipcrm -q 262144(ID) : ipc의 큐를 삭제함 (mspid=262144인 메세지 큐)
ipcrm -q 262145(ID) : ipc의 큐를 삭제함
## message queue
### msgsend.c
// 메세지를 보내는 프로그램
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <string.h>
int main ()
{
int msgqid;
key_t key; // 메세지 큐의 고유한 아이디
char buf[100];
key = 1234;
msgqid = msgget (key, IPC_CREAT | 0666); // 새로운 큐가 만들어짐
printf ("msgqid = %d \n", msgqid);
printf ("Enter a string to send : ");
gets (buf);
msgsnd (msgqid, buf, strlen(buf) + 1, 0); //msgqid에 buf를 보내기
}
### msgrcv.c
// 메세지를 받는 프로그램
#include <stdio.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <string.h>
int main ()
{
int msgqid, nread;
key_t key;
char buf[100];
key = 1234;
msgqid = msgget (key, IPC_CREAT | 0666);
printf ("msgqid = %d \n", msgqid);
nread = msgrcv (msgqid, buf, 100, 0, 0); //메세지를 가져옴
printf ("nread = %d, buf =[%s] \n", nread, buf);
}
### msgsend2.c
// 다른 데이터타입으로 메시지 보내는 프로그램 -> string, int 보내기
#include <stdio.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <string.h>
int main ()
{
int msgqid;
key_t key;
char buf[100];
int data;
key = 1234;
msgqid = msgget (key, IPC_CREAT | 0666); //새로운 큐 만들기
printf ("msgqpid = %d \n", msgqid);
printf ("Enter a string to send : ");
gets (buf);
msgsnd (msgqid, buf, strlen(buf) + 1, 0); //string 메시지 보내기 (배열의 이름 자체가 포인터이므로 배열의 이름만 쓰면 됨)
printf ("Enter an integer to send : ");
scanf ("%d", &data);
msgsnd (msgqid, &data, sizeof(int), 0); //int 메시지 보내기 (int의 주소를 보내줘야 함)
}
### msgrcv2.c
// 다른 데이터타입으로 메시지 받는 프로그램 -> string, int 읽기
#include <stdio.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <string.h>
int main(){
key_t key = 1234;
int msgqid;
int nread;
char buf[100];
int data;
msgqid = msgget(key, IPC_CREAT | 0666);
printf("msgqid = %d \n", msgqid);
nread = msgrcv(msgqid, buf, 100, 0, 0);
nread = msgrcv(msgqid, &data, sizeof(int), 0, 0);
printf("nread %d buf = [%s] data = [%d] \n", nread, buf, data);
}
## shared memory
### shmwrite.c
// 공유 메모리에 쓰기
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>
int main(){
key_t key = 1234;
int shmid;
char *shmaddr;
char buf[100];
shmid = shmget(key, 1024, IPC_CREAT | 0666); // shared memory 만들기 (key, byte수, 없으면 생성하라는 옵션 | permission)
printf("shmid = %d \n", shmid);
shmaddr = shmat (shmid, NULL, 0); // shared memory를 attach. shmaddr주소의 메모리에 1024byte만큼 attach
printf("shmaddr = %p \n", shmaddr);
printf("Enter a string to write : ");
gets(buf);
strcpy(shmaddr, buf); //shared memory에 씀
shmdt(shmaddr); // 다 쓰면 돌려줌
}
### shmread.c
// 공유 메모리 읽기
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>
int main(){
key_t key = 1234;
int shmid;
char *shmaddr;
char buf[100];
shmid = shmget(key, 1024, IPC_CREAT | 0666);
printf("shmid = %d \n", shmid);
shmaddr = shmat (shmid, NULL, 0);
printf("shmaddr = %p \n", shmaddr);
strcpy(buf,shmaddr); // shmaddr에 있는 내용을 buf로 copy
printf("buf = [%s]\n", buf);
shmdt(shmaddr);
}
### shmwrite2.c
// shared memory에 int형으로 쓰기
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
int main ()
{
int shmid;
int data;
char *shmaddr;
key_t key = 1235;
shmid = shmget (key, sizeof(int), IPC_CREAT | 0666);
printf ("shmid = %d \n", shmid);
shmaddr = shmat (shmid, NULL, 0); //변수의 주소
printf ("shmaddr = %p \n", shmaddr);
printf ("Enter an integer to write: ");
scanf ("%d", &data);
*((int*)shmaddr) = data; //int형으로 쓰려면 -> shmaddr를 int형으로 type casting후, 거기에 써야 하므로, *를 붙여줌
shmdt (shmaddr);
}
### shmread2.c
// shared memory에서 int형 메모리 읽기
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
int main ()
{
int shmid;
int data;
char *shmaddr;
key_t key = 1235;
shmid = shmget (key, sizeof(int), IPC_CREAT | 0666);
printf ("shmid = %d \n", shmid);
shmaddr = shmat (shmid, NULL, 0);
printf ("shmaddr = %p \n", shmaddr);
data = *((int*)shmaddr);
printf ("data = %d \n", data);
shmdt (shmaddr);
}
## [실습]
(1) mesg queue 이용한 메시지 전달하기
- program A
+ 키보드로 입력받은 문자열을 program B에 전달하고, program B가 보내는 문자열을 기다린다.
+ 만든 문자열을 출력한다.
+ 이 과정을 "end"를 입력할 때까지 반복한다.
- program B
+ program A로부터 문자열을 기다린다.
+ 받은 문자열을 출력하고, 새로운 문자열을 만든다. ("예: strcat을 사용해서 msg + "이름")
+ 새로 만든 문자열을 program A에게 전송한다.
+ 이 과정을 program A가 "end"를 받을 때까지 반복한다.
(2) 제출물
- 두 개의 프로그램 소스 코드
- 실행화면 캡쳐한 이미지 파일
### A.c
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <string.h>
//program A2
int main(){
// A
int msgqid;
key_t key;
char buf[100];
// B
int nread2;
int msgqid2;
key_t key2;
char buf2[100];
key = 1234;
msgqid = msgget (key, IPC_CREAT | 0666);
key2 = 1235;
msgqid2 = msgget (key2, IPC_CREAT | 0666);
while(1){
// program A : key = 1234에 쓰기
printf("This is Program1\n");
//printf ("msgqpid = %d \n", msgqid);
printf ("Enter a string to send in program A: ");
gets (buf);
msgsnd (msgqid, buf, strlen(buf) + 1, 0);
if (!strcmp(buf, "end")){exit(0);}
// program B : key = 1235에서 읽기
printf("This is Program2\n");
//printf ("msgqpid2 = %d \n", msgqid2);
nread2 = msgrcv (msgqid2, buf2, 100, 0, 0);
printf ("nread = %d, buf =[%s] \n", nread2, buf2);
}
}
### B.c
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <string.h>
//program B2
int main(){
// B
int msgqid;
key_t key;
char buf[100];
// A
int nread2;
int msgqid2;
key_t key2;
char buf2[100];
key2 = 1234;
msgqid2 = msgget (key2, IPC_CREAT | 0666);
key = 1235;
msgqid = msgget (key, IPC_CREAT | 0666);
while(1){
// program B : key = 1234에서 읽기
printf("This is Program1\n");
//printf ("msgqpid2 = %d \n", msgqid2);
nread2 = msgrcv (msgqid2, buf2, 100, 0, 0);
printf ("nread = %d, buf =[%s] \n", nread2, buf2);
strcat(buf2, "bokyung");
printf ("nread = %d, buf =[%s] \n", nread2, buf2);
// program B : key = 1235에 쓰기
printf("This is Program2\n");
//printf ("msgqpid = %d \n", msgqid);
msgsnd (msgqid, buf2, strlen(buf2) + 1, 0); //문자열+bokyung보내기
}
}
'Linux' 카테고리의 다른 글
[Linux] thread programming, mutex lock, semaphore in thread programming (0) | 2022.12.13 |
---|---|
[Linux] semaphore (0) | 2022.12.12 |
[Linux] fork, pipe, mkfifo (0) | 2022.12.11 |
[Linux] programming shell, execvp, fork (0) | 2022.12.09 |