제15장 프로세스 간 통행 15.6 XSI IPC 15.7 메시지 대기열

6621 단어
15.6 XSI IPC
(1) XSI IPC라는 3가지 IPC는 다음과 같습니다.
1) 메시지 대기열
2) 신호량
3) 공유 스토리지
(2) 식별자 및 키
1) 식별자: IPC 구조를 참조하는 비 음수 정수입니다.은 IPC 객체의 내부 이름입니다.
2) 키: IPC 객체의 외부 이름입니다.여러 협력 프로세스가 동일한 IPC 객체에 모이도록 할 수 있습니다.
(3)IPC_PRIVATE 키:
새 IPC 구조를 생성할 수 있습니다.이 키를 지정하여 기존 IPC 구조를 참조할 수 없습니다.
(4) ftok 함수:
경로 이름과 항목 ID에 의해 키가 생성됩니다.
(5)ipc_perm 구조체
ipc 구조의 권한과 소유자를 규정했습니다.
(6) 구조적 제한:
XSI IPC 패브릭에는 커널을 재구성하여 변경할 수 있는 내부 한계가 있습니다.
1)sysctl 명령: 커널 구성 매개변수를 관찰, 수정합니다.
2) ipcs -l: ipc 관련 제한을 표시합니다.
(7) IPC 구조와 파이프, FIFO의 차이점:
IPC 구조는 참조 수가 없는 시스템 내에서 작동합니다.
(8) IPC 구조는 파일 시스템에 이름이 없습니다.IPC에서 파일 설명자를 사용하지 않습니다.
15.7 메시지 대기열
(1) 새 프로그램에서 메시지 대기열을 사용하지 마십시오.그것들은 결점이 있다.(15.6.4)
(2) 클라이언트 프로세스와 서버 프로세스 사이의 양방향 데이터 흐름은 메시지 대기열이나 듀플렉스 파이프를 사용할 수 있다.
15.8 신호량
(1) 여러 프로세스 간에 하나의 자원을 공유하고 신호량, 기록 자물쇠와 상호 배척량 중 하나를 사용하여 조화롭게 할 수 있다.
(2) 공유 저장소에서 상호 배척량이 가장 빠르지만 작가는 기록 자물쇠를 사용하는 두 가지 이유를 좋아한다.
    1)<459>
    2)<459>
15.9 공유 스토리지
(1) 공유 스토리지의 역할:
두 개 이상의 프로세스가 주어진 저장소를 공유할 수 있도록 합니다.
이것은 가장 빠른 IPC이다. 왜냐하면 데이터는 고객 프로세스와 서버 프로세스 사이에서 복제할 필요가 없기 때문이다.
(2) 공유 스토리지를 사용할 때 습득해야 할 유일한 노하우:
동기화: 쓰고 읽기.(신호량, 기록 자물쇠와 상호 배척량)
(3)
shmget 함수: 공유 메모리 식별자를 얻습니다.
shmctl 함수: 공유 메모리 세그먼트에 대해 여러 가지 작업을 수행합니다.
shmat 함수: 공유 메모리 세그먼트를 프로세스의 주소 공간에 연결합니다.
shmde 함수: 호출 프로세스를 공유 저장소에서 분리합니다.
(4) 예: 특정 시스템에 저장된 다양한 유형의 데이터의 위치 정보를 인쇄합니다.
#include "apue.h"
#include <sys/shm.h>

#define	ARRAY_SIZE	40000
#define	MALLOC_SIZE	100000
#define	SHM_SIZE	100000
#define	SHM_MODE	0600	/* user read/write */

char	array[ARRAY_SIZE];	/* uninitialized data = bss */

int
main(void)
{
	int		shmid;
	char	*ptr, *shmptr;

	printf("array[] from %p to %p
", (void *)&array[0],   (void *)&array[ARRAY_SIZE]);//bss printf("stack around %p
", (void *)&shmid); if ((ptr = malloc(MALLOC_SIZE)) == NULL)// err_sys("malloc error"); printf("malloced from %p to %p
", (void *)ptr,   (void *)ptr+MALLOC_SIZE); if ((shmid = shmget(IPC_PRIVATE, SHM_SIZE, SHM_MODE)) < 0) err_sys("shmget error"); if ((shmptr = shmat(shmid, 0, 0)) == (void *)-1) err_sys("shmat error"); printf("shared memory attached from %p to %p
", (void *)shmptr,   (void *)shmptr+SHM_SIZE); if (shmctl(shmid, IPC_RMID, 0) < 0) err_sys("shmctl error"); exit(0); }

(5) C 프로그램의 저장 공간 레이아웃<163>
1) 본문 세그먼트: CPU가 실행하는 기계 명령 섹션
2) 데이터 세그먼트 초기화: (데이터 세그먼트), 프로그램에 초기값을 명확하게 부여해야 하는 변수를 포함한다.
3) 초기화되지 않은 데이터 세그먼트: (bss세그먼트) 프로그램이 실행되기 전에 이 세그먼트의 데이터를 0 또는 빈 바늘로 초기화합니다.(초기화되지 않은 글로벌 변수)
4) 스택: 자동 변수와 함수 호출 때마다 필요한 정보를 저장합니다.
5) 더미: 동적 저장 분배를 진행한다.
(6) 실례: 관련 프로세스의 다른 공유 저장소를 실현하는 기술.
1)/dev/zero의 메모리 매핑 2) 스레드
#include "apue.h"
#include <fcntl.h>
#include <sys/mman.h>

#define	NLOOPS		1000
#define	SIZE		sizeof(long)	/* size of shared memory area */

static int
update(long *ptr)
{
	return((*ptr)++);	/* return value before increment */
}

int
main(void)
{
	int		fd, i, counter;
	pid_t	pid;
	void	*area;

	if ((fd = open("/dev/zero", O_RDWR)) < 0)
		err_sys("open error");
	if ((area = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
	  fd, 0)) == MAP_FAILED)
		err_sys("mmap error");
	close(fd);		/* can close /dev/zero now that it's mapped */

	TELL_WAIT();

	if ((pid = fork()) < 0) {
		err_sys("fork error");
	} else if (pid > 0) {			/* parent */
		for (i = 0; i < NLOOPS; i += 2) {
			if ((counter = update((long *)area)) != i)
				err_quit("parent: expected %d, got %d", i, counter);

			TELL_CHILD(pid);
			WAIT_CHILD();
		}
	} else {						/* child */
		for (i = 1; i < NLOOPS + 1; i += 2) {
			WAIT_PARENT();

			if ((counter = update((long *)area)) != i)
				err_quit("child: expected %d, got %d", i, counter);

			TELL_PARENT(getppid());
		}
	}

	exit(0);
}

1) open에서/dev/zero 장치 읽기/쓰기
2) mmap 함수 매핑 저장소 fd----->void*를 호출합니다.(장점: 이 함수를 호출하여 맵을 만들기 전에 실제 파일이 존재하지 않아도 됩니다.)
3)close fd 닫기
4) 모/자 프로세스에서 TELL 사용CHILD(),TELL_PARENT(),WAIT_CHILD(),WAIT_PARENT () 동기화 (이 함수들은 SIGUSR1과 SIGUSR2 신호를 통해 동기화됩니다).
#include "apue.h"

static volatile sig_atomic_t sigflag; /* set nonzero by sig handler */
static sigset_t newmask, oldmask, zeromask;

static void
sig_usr(int signo)	/* one signal handler for SIGUSR1 and SIGUSR2 */
{
	sigflag = 1;
}

void
TELL_WAIT(void)
{
	if (signal(SIGUSR1, sig_usr) == SIG_ERR)
		err_sys("signal(SIGUSR1) error");
	if (signal(SIGUSR2, sig_usr) == SIG_ERR)
		err_sys("signal(SIGUSR2) error");
	sigemptyset(&zeromask);
	sigemptyset(&newmask);
	sigaddset(&newmask, SIGUSR1);
	sigaddset(&newmask, SIGUSR2);

	/* Block SIGUSR1 and SIGUSR2, and save current signal mask */
	if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
		err_sys("SIG_BLOCK error");
}

void
TELL_PARENT(pid_t pid)
{
	kill(pid, SIGUSR2);		/* tell parent we're done */
}

void
WAIT_PARENT(void)
{
	while (sigflag == 0)
		sigsuspend(&zeromask);	/* and wait for parent */
	sigflag = 0;

	/* Reset signal mask to original value */
	if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
		err_sys("SIG_SETMASK error");
}

void
TELL_CHILD(pid_t pid)
{
	kill(pid, SIGUSR1);			/* tell child we're done */
}

void
WAIT_CHILD(void)
{
	while (sigflag == 0)
		sigsuspend(&zeromask);	/* and wait for child */
	sigflag = 0;

	/* Reset signal mask to original value */
	if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
		err_sys("SIG_SETMASK error");
}

1)
int sigsuspend(const sigset_t *mask);
신호가 도착할 때까지 임시로 신호 마스크를 바꾸고 끊습니다.
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
이것은 신호 마스크를 되돌리는 데 사용됩니다.
kill 함수: 프로세스에 신호를 보냅니다.
(7) 실례: 익명 저장 맵.
익명: 파일 설명자를 통해 경로 이름과 결합하지 않고 후대 프로세스와 공유할 수 있는 저장소를 만듭니다.
(8) 관계없는 두 프로세스 간에 스토리지 세그먼트를 공유하는 방법:
1) XSI 공유 스토리지 함수
2) mmap은 같은 파일을 주소 공간에 매핑합니다.
15.10 POSIX 신호량
(1) POSIX 신호량 인터페이스는 XSI 신호량 인터페이스의 몇 가지 결함을 해결하는 것을 의미한다.
(2) 두 가지 형식:
1) 명명되지 않은 신호량: 메모리에만 존재하며, 신호량을 사용할 수 있는 프로세스가 메모리에 접근해야 합니다.(동일한 프로세스의 스레드 또는 매핑된 메모리)
2) 명명 신호량: 이름을 통해 접근할 수 있으며, 이름이 알려진 프로세스의 모든 라인에서 사용할 수 있다.
(3) POSIX 신호량의 Linux는 파일을 프로세스 주소 공간에 비추고 시스템 호출을 사용하여 각자의 신호량을 조작하지 않았다.
(XSI 신호량보다 뛰어난 성능)
15.12 소결
(1) 권장사항: 파이핑 및 FIFO 사용;메시지 대기열과 신호량의 사용을 피하기 위해 듀플렉스 파이프와 기록 자물쇠를 고려합니다.

좋은 웹페이지 즐겨찾기