Create
- int pipe(int pipefd[2]);
- int pipe(int pipefd[2], int flags);
creates a pipe, a unidirectional data channel
- data written to the write end of the pipe is buffered by the kernel until it is read from the read end of the pipe
pipefd[] is used to return two file descriptors referring to the ends of the pipe
- pipefd[0]: read end
- pipefd[1]: write end
- pipe()의 인자로 int타입 배열을 넣어주면 r/w ends을 return해준다.
flags
- O_CLOEXEC, O_DIRECT, O_NONBLOCK
- O_NONBLOCK은 read()/write()에서 데이터를 읽어오거나 쓸 수 없을 때, 프로세스가 잠을 자는, Blocked되는 상황을 막는다.
On success, zero is returned, On error, -1 is returned
Read
- ssize_t read(int fd, void *buf, size_t count);
Attemps to read up to count bytes from file descriptor fd into the buffer starting at buf
On success, the number of bytes read and buffered is returned; When the end of the data is reached, 0 is returned
- count를 buffer의 size보다 크게 설정한다면 overflow가 발생할 수 있다
- read()의 return value는 실제로 읽어낸 데이터의 사이즈인데, 이 값이 count와 다를 수도 있다
- the end of data는 더 이상 보낼 data가 없다는 의미로, write쪽이 모두 close되면 EOD가 pipe에 저장, 그것을 읽고 0을 리턴한다
- Data는 없지만 write가 close가 아닌 상태 (pipe가 비어있는 상태) 에서 read를 하면 data가 들어올 때까지 잠든다. (CPU자원을 사용하지 않는다) 그러다 다시 write이 되면 읽는다
Write
- ssize_t write(int fd, const void *buf, size_t count);
Writes up to count bytes from the buffer starting at buf to the file referred to by the file descriptor df
On success, the number of bytes written is returned; On error, -1 is returned
- Count만큼 넣으려 했지만 return값과 다를 수 있다 (write하다가 pipe가 꽉 찬 경우)
- Pipe가 꽉 차서 못 넣는 경우는 반대편에서 read()를 할 때 까지 잠을 잔다
Close
- int close(int fd);
Closes a file descriptor
On success, 0 is returned; On error, -1 is returned
Example
int main(int argc, char *argv[])
{
int pipefd[2];
pid_t cpid;
char buf;
if (argc != 2){
fprintf(stderr, "Usage: %s <string>\n", argv[0])
exit(EXIT_FAILURE);
}
if (pipe(pipefd) == -1){
perror("pipe");
exit(EXIT_FAILURE);
}
cpid = fork();
if (cpid == -1){
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0){ /* Child reads from pipe */
close(pipefd[1]); /* Close unused write end */
while (read(pipefd[0], &buf, 1) > 0)
printf("%c", &buf);
printf("\n");
close(pipefd[0]);
exit(EXIT_SUCCESS);
}
else { /* Parent writes argv[1] to pipe */
close(pipefd[0]); /* Close unused read end */
write(pipefd[1], argv[1], strlen(argv[1]);
close(pipefd[1]);
wait(NULL);
exit(EXIT_SUCCESS);
}
}
+ child에서 close(pipefd[1]) 할 때, pipe의 wirte end가 모두 닫히는 건 아니다. reference count라고 kernel은 공유하는 자원에 대해서 사용하는 process의 개수를 파악하고 있기 때문에, child에서 close를 해도 parent가 남아있어서 아에 close되는 것은 아니다.
+ child의 while loop는 parent에서 close를 할 때 탈출한다. data가 없으면 (아직 parent에서 close는 안했고) 반대편에서 write할 때까지 프로세스가 잠자기 때문에 while loop을 탈출한 것은 아니다.
Named Pipes (FIFO)
- int mkfifo(const char *pathname, mode_t mode);
Makes a FIFO special file with name pathname
mode specifies the FIFO's permissions
Once you have created a FIFO special file in this way, any process can open it for reading or writing, in the same way as an ordinary file
- fork를 통해 fd를 부모/자식 간에 공유하지 않고, 아에 서로 독립적인 process들의 IPC를 위해서 사용하는 pipe로, pipe의 경로를 통해 서로 공유할 수 있다.
- 이때 FIFO는 OS가 pipe로 사용할 수 있도록 만든 가상 file이다.
'[학교 수업] > [학교 수업] 시스템 프로그래밍' 카테고리의 다른 글
[시스템 프로그래밍] Threads (2) | 2024.10.30 |
---|---|
[시스템 프로그래밍] Message Queue (3) | 2024.10.17 |
[시스템 프로그래밍] Inter-Process Communication (3) | 2024.10.11 |
[시스템 프로그래밍] Real-Time Signal (5) | 2024.10.08 |
[시스템 프로그래밍] Assembly Language (1) | 2024.10.06 |