커널의 종류
모놀리딕 - 커널과 동일한 메모리공간에 입출력,네트워크,장치 드라이버 적재 linux
마이크로 - 기본적인 기능만 적재, 필요에 따라 추가 window
하이브리드 - 모놀리딕+마이크로
모놀리딕
가상 파일 시스템
ipc, 파일 시스템
스케줄러, 가상 메모리
장치드라이버, 디스패쳐
마이크로
ipc기본
가상메모리
스케줄링
ap ipc,장치드라이버,파일서버 -> 사용자모드 에서 동작한다.
window에선 각종 장치드라이버를 따로 설치 해야 하는것은 쓰다보면 알수있다.
ipc란? (Inter-Process Communication)
리눅스에서 지원하는 c언어 api를 이용해 코딩 해보자.
fork 함수는 코드를 그대로 복사해 실행한다고 보면 된다.
즉 프로세스가 하나 더 생기는것. 이때 복사한 프로세스를 자식프로세스라 한다.
부모 프로세스는 양수인 pid값을 부여받고 자식프로세스는 0을 부여받는다.
*pid는 os에서 프로세스를 식별하는 id값이며 PCB에 저장된다.
이 코드를 실행하면 메모리에는 실제로 같은 두개의 코드가 메모리에 존재하는것 이다.
출력결과를 보자면 oxoxoxox이런식이 아닌 oooooooooooooooooooxxxxxxxxxxxxxxxxxxxxoooooooo............이런식으로 출력이 된다.
1) cpu는 하나의 프로세스만 실행하기 때문에 연속적인 출력을 하고
2) cpu는 하나의 프로세스를 무한정 실행시키지 않는다. os는 독점을 방지하기 위해 일정시간이 지나면 다른 프로세스에 cpu를 할당한다.
*자식프로세스가 fork함수로 인해 자식의 자식 프로세스를 무한정 생성하지 않을까?
os는 fork함수는 부모프로세스에서 한번만 실행되게 한다.
즉 자식 프로세스는 fork함수로 프로세스 복제를 안하고 pid만 부여 받는다.
프로세스 vs 실행중인 프로그램
- cpu를 할당의 차이. 보통 일반가정집의 cpu는 하나이기 때문에 하나의 프로세스만 처리 가능하다.
-메모리에는 여러개의 프로세스가 존재한다.
-실제 메모리 크기보다 더 많은 프로세스를 배치하기 위하여 사용하는것이 가상메모리 기법이다.
2. pipe함수 이해
파일 디스크립터 - 프로세스가 파일을 구별하는 id값(식별자) 이다. os가 할당해준다.
-리눅스의 경우는 소켓과 파일을 구별하는 디스크립터를 구분 하지 않는다.
-파일 디스크립터를 이용해 FCB(file control block : 파일정보)에 접근한다.
-표준입출력,에러 많이 쓰이는 파일은 0,1,2로 정해져 있다.
int pipe(int filedes[2]);
인자 : filedes[2] - 배열 인덱스 0은 수신파일의 파일디스크립터, 배열 인덱스 1은 발신파일의 파일디스크립터이다.
사용자는 이 파일 디스크립터를 이용하여 송.수신을 한다.
반환 값 : 성공시 0, 실패시 -1
#include <stdlib.h>
#include <stdio.h>
int main()
{
int n, fd[2];
char buf[255];
int pid;
if (pipe(fd) < 0) //송수신 파일 디스크립터를 할당 받는다.
//송신 파이프
//수신 파이프
//파이프도 파일이다
{
perror("pipe error : ");
exit(0);
}
// 파이프를 생성한다.
if ((pid = fork()) < 0) //자식프로세스는 fork 함수를 실행하지 않는다. id만 부여받는다.
{
perror("fork error : ");
exit(0);
}
// 만약 자식프로세스라면 파이프에 자신의 PID 정보를 쓴다.
else if (pid == 0)
{
close(fd[0]); // 수신 파일은 미사용
while(1)
{
memset(buf, 0x00, 255);
sprintf(buf, "Hello Mother Process. My name is %d\n", getpid());
write(fd[1], buf, strlen(buf));
sleep(1); //프로세스를 대기상태로 일정시간 동안 만든다.
}
}
// 만약 부모프로세스라면 파이프에서 데이타를 읽어들인다.
else
{
close(fd[1]); //송신 파일은 미사용
while(1)
{
memset(buf, 0x00, 255);
n = read(fd[0], buf, 255);
fprintf(stderr, "%s", buf);
}
}
}
pipe는 반이중통신이라
전이중 통신으로 만들려면 코드가 복잡해진다.
3.메세지큐 사용
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg); //메세지큐 생성(os에서 식별하는 메세지큐, 권한설정)
//반환 큐식별자값
int msgsnd (int msqid, (void *)msgp, size_t msgsz, int msgflg)
ssize_t msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz,
long msgtyp, int msgflg)
- msqid : msgget를 이용해서 생성된 메시지큐 지시번호.
- msgp : 보내고자 하는데이터.
- msgsz : 보내고자 하는데이터의 크기
- msgtyp : 읽고자하는 메시지의 타입.
- msgtyp이 0이라면 큐의 첫번째 데이터를 읽어들인다.
- msgtyp가 0보다 크면, 커널은 큐에서 msgtyp 번호를 가지는 가장 오래된 메시지를 찾아내서 되돌려진다.
- msgflg : IPC_NOWAIT가 지정되면 비봉쇄모드로 작동한다. 즉 이용가능한 메시지가 없으면 기다리지 않고 바로 ENOMSG 를 반환한다. 그렇지 않으면 큐에 읽을 데이터가 쌓일때까지 기다린다.
struct msgbuf
{
long mtype; // 메시지 타입
char mtext[BUFF_SIZE]; // 보내고자 하는 데이터
}
송신측
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
typedef struct {
long mtype; /* message type, must be > 0 */
char mtext[16]; /* message data */
} MsgType;
void main(){
key_t key = 4499;
int que_id = msgget(key, IPC_CREAT | 0600);
char mtext[6] = "hello";
MsgType msg;
int msg_size = 0;
msg.mtype = 100; // pid = 생성한 process id 중 하나.
strcpy(msg.mtext, "hello!!");
msg_size = sizeof(msg) - sizeof(msg.mtype);
// que_id는 msgget()을 통해 얻은 값
int rtn = msgsnd(que_id, &msg, msg_size, 0);
if (rtn == -1) {
printf("msgsnd() fail\n");
}
}
생성한 메세지큐는 ipcs -q 명령어로 확인한다.
수신측
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
typedef struct {
long mtype; /* message type, must be > 0 */
char mtext[16]; /* message data */
} MsgType;
void main(){
key_t key = 4499;
int que_id = msgget(key, IPC_CREAT | 0600);
MsgType msg;
ssize_t nbytes = 0;
int msg_size = 0;
msg_size = sizeof(msg) - sizeof(msg.mtype);
// pid = 자신의 process id, getpid() 함수로 얻을 수 있다.
nbytes = msgrcv(que_id, &msg, msg_size, 100, IPC_NOWAIT);
if (nbytes > 0)
{
printf("recv msg form msgque, bytes(%d)\n", nbytes);
// 수신한 메시지 처리.. 함수는 알아서 구현~~
//procIpcMsg(msg);
printf("recv : %s\n",msg.mtext);
}
else
{
if (nbytes == 0)
{
printf("no exist msg\n");
}
else
{
printf("msgrcv() error\n");
return ;
}
}
}
이외에도 공유메모리,메모리맵,세마포어 가 있다 . 난중에 추가예정..
https://www.joinc.co.kr/w/Site/system_programing/Book_LSP/ch08_IPC 참조