|
|
프로세스 종료를 기다린다.
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status); |
주로 fork() 를 이용해서 자식 프로세스를 생성했을때 사용한다.
wait() 를 쓰면 자식프로세스가 종료할때까지 해당영역에서
부모프로스쓰가 sleep 모드로 기다리게 된다.
이는 자식프로세스와 부모프로세스의 동기화를 위한목적으로
부모프로세스가 자식프로세스보다 먼저 종료되어서 자식프로세스가
고아 프로세스(PPID 가 1)인 프로세스가 되는걸 방지하기 위한
목적이다.
만약 자식 프로세스가 종료되었다면 함수는 즉시 리턴되며,
자식이 사용한 모든 시스템자원을 해제한다.
그런데 어떤이유로 부모가 wait()를 호출하기 전에 자식 프로세스가
종료버리는 경우도 있다(잘못된 메모리 연산등으로 인한 죽음,
혹은 정상적으로), 이럴경우
자식프로세스는 좀비프로세스가 되는데, wait()함수는 즉시
리턴하도록 되어있다.
wait()의 인자 status 를 통하여 자식 프로세스의 상태를 받아올수
있는데, 자식프로세스의 상태값은 자식프로세스의 종료값 * 256(FF) 이다.
종료된 자식의 프로세스 ID는 에러일경우 -1 그렇지 않을경우
0을 반환한다.
다양한 원인에 의해서 에러가 발생할수 있으며 아래와 같은 에러 메시지들이 있다.
- ECHILD
pid 로 지정된 프로세스가 존재하지 않거나, 해당 pid 가
자신의 자식 프로세스가 아닐경우
- ENOTSOCK
s 가 소켓이 아닌 파일일경우
- ENOTCONN
소켓이 연결되어 있지 않을경우
- ENOBUFS
시스템에 연산을 위해서 이용할수 있는 자원이 부족할때
#include <sys/types.h>
#include <sys/wait.h> #include <unistd.h> #include <string.h>
int main() { int pid; int status;
pid = fork(); // 자식 프로세스 if (pid < 0) { perror("FORK ERROR :"); exit(0); }
if (pid == 0) { int i; for (i = 0; i < 5; i++) { printf("Child : %d\n", i); sleep(2); } exit(3); } else { // 부모프로세스는 자식프로세스가 // 종료할때까지 기다린다. printf("I wait Child(%d)\n", pid); wait(&status); printf("Child is exit (%d)\n", status); } } |
위의 예제를 컴파일후 실행시키면 다음과 같은 결과를 보여준다.
[root@localhost c_source]# ./wait I wait Child(12128) Child : 0 Child : 1 Child : 2 Child : 3 Child : 4 Child is exit (768) |
이 문서는 수정될 수 있습니다. 최신문서는 Joinc Wiki에서 :::

파일기술자가 가리키는 파일에 쓴다. 이 파일기술자는 open(2), socket(2) 등으로
얻을수 있다.
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count); |
첫번째 아규먼트인 fd 는 열린파일 기술자이다. 이것은 보통 open(2), socket(2) 등으로
만들어지며, 때때로 pipe(2) 등으로 만들어지기도 한다.
두번째 아규먼트는 fd 로 쓸 데이타이며, count 는 fd 쓸
데이타의 크기이다.
성공할경우 쓰여진 바이트 만큼이 리턴된다. 0이면 쓰여진것이 없음을 나타내며,
-1 일경우는 에러가 발생했을 경우이다. 에러가 발생했을경우에는 errno 에 적당한
값이 설정된다.
다양한 원인에 의해서 에러가 발생할수 있으며 아래와 같은 에러 메시지들이 있다.
- EBADF
fd 가 유효한 파일 기술자가 아니거나 쓰여질수 없도록 열려있을경우
- EINVAL
fd 가 쓰기에 적당하지 않은 객체와 연결되어 있을경우
- EFAULT
buf 가 접근할 수 없는 주소 공간을 가리키고 있을때
- EPIPE
fd 가 끝이 닫혀진 소켓이나 파이프에 연결되어 있을때.
쓰고 있는 프로세스가 SIGPIPE signal를 받았을때 발생한다.
- EAGAIN
fd 가 비봉쇄(O_NONBLOCK) 로 열렸을경우, 데이터를 쓰기 위해 fd 와
연결된 파이프나 소켓에 공간이 없을때, 발생한다. 봉쇄로 열렸을경우에는
연결된 파이프나 소켓에 공간이 있을때까지 봉쇄된다.
- EAGAIN
fd 가 비봉쇄(O_NONBLOCK) 로 열렸을경우, 데이터를 쓰기 위해 fd 와
연결된 파이프나 소켓에 공간이 없을때, 발생한다. 봉쇄로 열렸을경우에는
연결된 파이프나 소켓에 공간이 있을때까지 봉쇄된다.
#include <fcntl.h>
#include <unistd.h> #include <stdio.h>
struct data { int age; char name[25]; }; int main() { int fd; int n; struct data mydata, readdata;
fd = open("data.txt", O_CREAT|O_RDWR); if (fd == -1) { perror("open error : "); }
mydata.age = 25; strcpy(mydata.name, "hello"); n = write(fd, (void *)&mydata, sizeof(mydata)); close(fd); } |
이 예제는 data.txt 라는 파일을 일기/쓰기 모드로 open 한 다음에
data 구조체를 파일에 적는 프로그램이다. 이 문서는 수정될 수 있습니다. 최신문서는 Joinc Wiki에서.. :::

inode 에 대한 접근/수정 시간을 변경한다.
#include <sys/types.h> #include <utime.h>
int utime(const char *filename, struct utimbuf *buf); |
utime()는 filename으로 지정된 inode 의
접근 시간과 수정시간을 buf의 actime 과 modtime 값으로
각각 변경한다. 만약 buf 가 NULL 이라면, 파일의 접근 시간과
수정시간은 현재 시간으로 설정된다.
다음은 utimebuf 구조체이다.
struct utimbuf { time_t actime; // 접근시간 time_t modtime; // 변경시간 }; |
성공시 0을 리턴하며, 에러때는 -1을 리턴한다.
다양한 원인에 의해서 에러가 발생할수 있으며 아래와 같은 에러 메시지들이 있다.
- EACCESS
파일에 대한 권한이 거부되었다.
- ENOENT
파일이 존재하지 않는다.
#include <sys/types.h> #include <utime.h> #include <sys/time.h> #include <stdio.h> #include <string.h>
int main() { struct utimbuf ubuf; ubuf.actime = time((time_t *)0); ubuf.modtime = time((time_t *)0);
// 접근,수정 시간을 현재 시간으로 변경한다. utime("sizeof.c", NULL);
// NULL 대신 actime,modtime 을 세팅해서 // 직접 값을 지정해줄수도 있다. utime("sizeof.c", &ubuf); } |
:::

파일을 이름으로 지운다. 필요할경우 참조하는 파일도 지운다.
#include <unistd.h>
int unlink(const char *pathname); |
unlink 는 파일 시스템에서 pathname 이름을 가진 파일을 지운다. 만약
지우려는 파일이 파일에 대한 가장최근연결(링크가 오직 하나라면) 이며,
다른 어떠한 프로세스도 이 파일을 열고 있지 않다면, 파일은 지워지고,
파일이 사용한 공간은 사용가능하도록 파일시스템에 되돌려준다.
만약 지우려는 파일의 가장 최근 연결된 파일이지만, 이 파일을 다른 프로세스가
열고 있다면, 다른 프로세스가 이 파일을 닫을때까지 파일은 존재한체로 남게
되다.
만약 pathname이 심볼릭 링크파일이라면 연결은 제거된다.
성공할경우 0을 실패했을경우에는 -1을 반환하며, 적당한 errno 값을
설정한다.
다양한 원인에 의해서 에러가 발생할수 있으며 아래와 같은 에러 메시지들이 있다.
- EACCESS
pathname 을 포함하는 디렉토리에 대한 쓰기접근이 허용되지 않았거나,
pathname 의 디렉토리중 어느 하나에 대한 실행 허가권을 가지고 있지 않을때
- EPERM
파일 pathname 이 디렉토리 파일일때.
- ENOTDIR
pathname 이 디렉토리를 가리킬때.
- EROFS
pathname 이 읽기전용의 파일시스템을 가리킬때
#include <unistd.h>
int main(int argc, char **argv) { if (access(argv[1], F_OK) !=0 ) { printf("파일 %s 가 존재하지 않습니다\n", argv[1]); exit(0); } unlink(argv[1]); printf("삭제 완료\n"); exit(0); } :::

현재커널에 대한 정보를 얻어온다.
#include <sys/utsname.h>
int uname(struct utsname *buf); |
커널에 대한 이름과 버젼정보등을 얻어온다.
utsname 구조체는 다음과 같다.
struct utsname { char sysname[SYS_NMLN]; char nodename[SYS_NMLN]; char release[SYS_NMLN]; char version[SYS_NMLN]; char machine[SYS_NMLN]; #ifdef _GNU_SOURCE char domainname[SYS_NMLN]; #endif }; |
성공할경우 0을 실패했을경우에는 -1을 반환하며, 적당한 errno 값을
설정한다.
#include <sys/utsname.h>
#include <stdio.h>
int main() { struct utsname buf; uname(&buf);
printf("%s : %s : %s\n", buf.sysname, buf.release, buf.machine); return 0; }
:::

터미널의 이름을 얻어온다.
#include <unistd.h>
char *ttyname(int desc); |
ttyname()는 열린파일 지정자
desc에 대한 터미널 이름을 얻어온다. 만약
터미널 이름을 가져오는데 실패 했다면 NULL을
되돌려 준다.
일반적으로 ttyname은 자신의 터미널이름을 가져오는데 사용되므로
프로세스가 만들어질 때 기본적으로 생성되는 파일지정자(0, 1, 2)에 대해서
적용하는 경우가 많다.
성공할 경우 터미널 장치명에 대한 포인터를 리턴한다. 에러가 발생할 경우
NULL를 리턴한다.
- EBADF
잘못된 파일 지정자
- ENOTTY
파일 지정자가 터미널을 가지고 있지 않다.
#include <unistd.h>
#include <stdio.h> int main() { printf("Your tty name is : %s\n", ttyname(0)); } 이 문서는 수정될 수 있습니다. 최신 문서는 Joinc Wiki에서..
:::

초 단위로 시간을 가져온다.
#include <time.h>
time_t time(time_t *t); |
이 함수가 돌려주는 시간은 1970년 1월 1일 00:00:00 부터
지금까지의 시간을 초단위로 환산한것이다.
만약 아규먼트로 들어가는 t 가 NULL 이 아니라면 반환값은 t 가
가르키는 메모리에 저장된다.
성공하면 현재까지의 흐른시간을 초단위로 리턴한다. 에러가 발생할경우
-1 이 리턴된다.
- EFAULT
t 가 가리키는 곳이 접근할수 없는 메모리 영역을
가르킬경우
#include <time.h>
#include <stdio.h> #include <unistd.h> #include <sys/types.h>
void swaptime(time_t, char *); int main() { int i; time_t the_time; char buffer[255];
// 현재 TIME 을 구한다. time(&the_time);
printf("현재 시간은 %d 초\n", the_time);
// 보기좋은 지역시간대로 바꾼다. swaptime(the_time, buffer); printf("%s\n", buffer); }
void swaptime(time_t org_time, char *time_str) { struct tm *tm_ptr; tm_ptr = localtime(&org_time);
sprintf(time_str, "%d/%d/%d %d:%d:%d", tm_ptr->tm_year+1900, tm_ptr->tm_mon+1, tm_ptr->tm_mday, tm_ptr->tm_hour, tm_ptr->tm_min, tm_ptr->tm_sec); } |
이 프로그램을 실행시키면 아래와 같은 결과 값을 보여줄것이다.
[root@s210-205-210-195 test]# ./time 현재 시간은 1030294567 초 2002/8/26 1:56:7
이 문서는 수정될 수 있습니다. 최신문서는 Joinc Wiki에서. :::

공유메모리 관련 연산
#include <sys/ipc.h> #include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg); int shmdt(const void *shmaddr); |
shmat()는 공유메모리 식별자인shmid에 공유 메모리
세그먼트를 붙이기 위해서 사용한다. 붙이는 영역은 shmaddr로
결정할 수 있다.
만약 shmaddr가 NULL이라면 시스템은 적당한 사용하지 않는 메모리
영역을 붙이게 된다.
만약 shmaddr가 NULL이 아니고 SHM_RND가 shmflg로 지정되어 있다면
shmaddr은 SHMLBA의 배수의 주소로 연결이 발생한다. 그렇지 않으면 shmaddr은 연결할 수
있는 정렬된 페이지 주소여야 한다.
만일 SHM_RDONLY가 shmflg에 지정되었다면, 세그먼트는 읽기전용이
되며 공유메모리 영역에 접근하고자 하는 프로세스는 읽기전용허가 접근권을 가져야 한다.
그렇지 않을경우 세그먼트는 읽기/쓰기로 붙여지며 프로세스는 (반드시)읽기/쓰기
허가권을 가져야한다. 쓰기전용 공유메모리 세그먼트를 위한 플래그는 없다.
프로세스가 종료되면 연결된 세그먼트는 자동적으로 분리된다. 동일한 세그먼트는
읽기와 읽기/쓰기로 한번이상 연결시킬 수 있다.
shmat가 성공하면 시스템은 shmid_ds구조체의 멤버들을 아래와 같이 업데이트 시킨다.
shm_atime을 현재 시간으로 수정한다.
shm_lpid를 현재 호출한 프로세스의 ID로 설정한다.
shm_nattch는 1 증가 시킨다.
공유메모리 세그먼트가 삭제로 표시될 때에도 마찬가지로 분리된다.
shmdt()는 공유 메모리 영역으로 부터 shmaddr 주쇼를 분리
시키기 위해서 사용한다. 공유메모리 영역의 분리는 shmat 시스템 콜로 연결된 값과
동일한 shmaddr을 가지고 있는 연결된 영역들중 하나여야 한다.
shmdt()가 성공적으로 호출되면 shmid_ds구조체의 멤버를 다음과 같이 변경한다.
shm_dtime을 현재 시간으로 변경한다.
shm_lpid를 현재 호출한 프로세스의 ID로 변경한다.
shm_nattch을 1 감소 시킨다. 만약 값이 0이되고 세그먼트에 삭제표시가 되어 있다면
세그먼트는 삭제된다.
호출 프로세스의 유저공간에 점유된 영역은 대응이 풀리지 않는다.
성공하면 attach된 shared memory segment를 반환하고 실패하면 -1을 반환한다.
- EACCES
호출한 프로세스가 붙이기 원하는 영역에 대해서 권한을 가지고 있지 않다.
- EINVAL
잘못된 shmid 값, 혹은 잘못된 shmaddr 값을 가지고 있다.
- ENOMEM
메모리할당을 할 수 없다.
#include <sys/ipc.h> #include <sys/shm.h> #include <string.h> #include <unistd.h>
int main() { int shmid; int pid;
int *cal_num; void *shared_memory = (void *)0;
// 공유메모리 공간을 만든다. // 크기는 4byte로 한다. shmid = shmget((key_t)1234, sizeof(int), 0666|IPC_CREAT);
if (shmid == -1) { perror("shmget failed : "); exit(0); }
// 프로세스 메모리를 공유메모리영역에 붙인다. shared_memory = shmat(shmid, (void *)0, 0); if (shared_memory == (void *)-1) { perror("shmat failed : "); exit(0); }
cal_num = (int *)shared_memory; pid = fork(); if (pid == 0) { shmid = shmget((key_t)1234, sizeof(int), 0); if (shmid == -1) { perror("shmget failed : "); exit(0); } shared_memory = shmat(shmid, (void *)0, 0666|IPC_CREAT); if (shared_memory == (void *)-1) { perror("shmat failed : "); exit(0); } cal_num = (int *)shared_memory; *cal_num = 1;
while(1) { *cal_num = *cal_num + 1; printf("child %d\n", *cal_num); sleep(1); } }
// 부모 프로세스로 공유메모리의 내용을 보여준다. else if(pid > 0) { while(1) { sleep(1); printf("%d\n", *cal_num); } } } |
공유 메모리를 이용한 프로세스간 데이터 교환
ftok(3)
ipc(5)
shmctl(2)
shmat(2)
shmdt(2)
이 문서는 수정될 수 있습니다. 최신문서는 Joinc Wiki에서 :::

공유메모리 영역을 할당한다.
#include <sys/ipc.h> #include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg); |
shmget()은 주어진 인자 key를 접근번호로 하는
공유메모리 공간할당을 커널에 요청한다. 커널에서 성공적으로 공유메모리
공간을 할당하게 되면 공유메모리를 가르키는 식별자를 리턴하게 된다.
생성될 공유메모리 공간의 크기는 size를 통해서
byte 단위 크기로 지정할 수 있다. 공간의 할당은
shmflg가 IPC_PRIVATE이거나 key
를 가지는 공유메모리영역이 존재하지 않거나, IPC_CREAT가 지정되었을 경우
(shmflg&IPC_CREAT가 0이 아닌)에 이루어진다.
다음은 사용가능한 shmflg값들이다.
- IPC_CREAT
새로운 영역을 할당한다. 만약 이 값이 사용되지 않았다면,
shmget()은 key로 이미 생성된 접근 가능한
공유메모리 영역이 있는지 확인하고 이에 대한 식별자를
되돌려줄 것이다.
- IPC_EXCL
IPC_CREAT와 함께 사용하며 공유메모리 영역이 이미 존재하면 에러를
리턴한다.
- mode_flags(하위 9bit)
접근 권한의 지정을 위해서 사용한다. 실행권한은 사용하지 않는다.
만약 새로운 영역이 생성되었다면 shmflg의 권한정보는 영역에 대한 정보가
정의되어 있는 shmid_ds 구조체의 멤버인 shm_perm으로 복사된다. shmid_ds
구조체는 아래와 같이 정의되어 있다.
struct shmid_ds { struct ipc_perm shm_perm; /* operation perms */ int shm_segsz; /* size of segment (bytes) */ time_t shm_atime; /* last attach time */ time_t shm_dtime; /* last detach time */ time_t shm_ctime; /* last change time */ unsigned short shm_cpid; /* pid of creator */ unsigned short shm_lpid; /* pid of last operator */ short shm_nattch; /* no. of current attaches */ };
struct ipc_perm { key_t key; ushort uid; /* owner euid and egid */ ushort gid; ushort cuid; /* creator euid and egid */ ushort cgid; ushort mode; /* lower 9 bits of shmflg */ ushort seq; /* sequence number */ }; |
만약 공유 메모리 영역이 이미 존재한다면 접근권한은 수정된다.
- fork()
attache된 공유 메모리 공간은 자식 프로세스에게 상속된다.
- exec()
exec()가 호출된 후에는 모든 공유 메모리 공간은 detache된다.
- exit()
exit()후 모든 공유 메모리 공간은 detache된다
(없어 지지는 않는다).
성공하면 shmid를 반환, 실패하면 -1을 반환한다.
- EINVAL
공유 영역생성시 너무 작은 공간을 할당 하거나(size < SHMMIN)
너무 큰 공간(size > SHMMAX)을 할당했을
경우
- EEXIST
- EACCESS
IPC_CREAT | IPC_EXCL 로 생성을 요청했는데, 이미 공유 메모리
영역이 존재하고 있을 경우,
- ENOSPC
size만큼의 공간을 할당할 수 없을 경우.
사용가능한 공간은 SHMALL값으로 커널전역적으로 정의되어 있다.
(/usr/include/linux/shm.h 참고)
- ENOENT
IPC_CREAT를 사용하지 않았는데, 해당 key를
가지는 공유 메모리 영역이 존재 하지 않는 경우
- EACCESS
공유 메모리 영역에 대한 접근권한이 주어져 있지 않다.
- ENOMEM
이용할 수 있는 커널 메모리가 충분하지 않다.
공유 메모리를 이용한 프로세스간 데이터 교환
ftok(3)
ipc(5)
shmctl(2)
shmat(2)
shmdt(2)
:::

|