리눅스 환경에서 C언어를 사용하여 빠른 프로세스간 통신(IPC)를 구현해야 할 때에 공유메모리를 사용할 수 있다. 그러나 한 프로세스가 데이터를 읽는 도중에 다른 프로세스가 해당 공간에 대해 쓰기 작업을 한다면 데이터 부정합이 발생할 수 있다. POSIX 세마포어 중 이름 있는 세마포어(named semaphore)를 사용하여 공유자원에 대한 동시 접근 문제를 해결할 수 있다.


 공유메모리를 사용하기 위해 아래와 같은 함수들을 사용해야 한다.

shmget() 

임의의 키값과 메모리크기를 매개면수로 주어 공유메모리 생성을 커널에 요청하고, 정상적으로 생성되었을시 id를 받아온다. 


shmat()

공유메모리를 현재 프로세스에 붙인다(attach) 반환값으로는 공유메모리의 포인터가 나오고 이 포인터를 통해 메모리에 접근할 수 있다.


shmdt()

공유메모리를 현재 프로세스에서 분리한다(detach)


shmctl()

공유메모리에 대한 제어를 한다. 여기서는 삭제를 위해 사용.

생성된 공유메모리에 대한 정보는
ipcs -m
명령으로 확인할 수 있다.




POSIX named 세마포어는 아래 함수들을 통해 사용할 수 있다.


sem_open()

named 세마포어를 생성하고 세마포어 구조체 포인터(sem_t *)를 받아온다.


sem_wait()

공유자원에 접근하기 전에 세마포어를 잠근다. 만약 해당 자원에 접근할 수 있는 프로세스가 최대 1개이고, 잠겨있는 상태이면 block되어 풀릴 때까지 대기한다.


sem_trywait()

sem_wait()의 논블로킹 함수로, 자원이 잠겨 있어도 일단 -1을 반환하며 함수가 종료되고, errno를 통해 추가적인 처리를 할 수 있다. 


sem_post()

공유자원에 대한 접근이 끝났을 때 세마포어 잠금을 해제한다.


sem_close()

해당 프로세스에서 세마포어를 닫는다.


sem_unlink()

세마포어를 파괴한다.



예제코드는 아래와 같이 컴파일하였다.

clang provicer.c -o provider -std=gnu99 -lpthread


provider.c

#include <stdio.h>

#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <semaphore.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>

int main(void)
{
    int shmid;
    size_t shsize = 1024;
    const int key = 16000;
    char *shm;

    sem_t *mysem;
    sem_unlink("mysem");
    if((mysem = sem_open("mysem", O_CREAT, 0777, 1)) == NULL) {
        perror("Sem Open Error");
        exit(1);
    }

    if((shmid = shmget((size_t)key, shsize, IPC_CREAT|0666))<0) {
        perror("shmget");
        exit(1);
    }

    if((shm = (char*)shmat(shmid, NULL, 0)) == (char*)-1) {
        perror("shmat");
        exit(1);
    }

    for(int i=0; i<100; i++) {
        shm[i] = 0;
    }


    for(;;) {
        sem_wait(mysem);
        for(int i=0; i<100; i++) {
            shm[i] = (shm[i]+1)%10;
        }
        usleep(1000*1000);
        sem_post(mysem);
        usleep(1000*1000);
    }

    getchar();

    sem_close(mysem);

    sem_unlink("mysem");

    shmdt(shm);
    shmctl(shmid, IPC_RMID, 0);


    return 0;
}


consumer.c

#include <stdio.h>

#include <unistd.h>
#include <semaphore.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>

int main(void)
{
    int shmid;
    size_t shsize = 1024;
    const int key = 16000;
    char *shm;

    sem_t *mysem;
    if((mysem = sem_open("mysem", 0, 0777, 0)) == SEM_FAILED) {
        perror("Sem Open Error");
        exit(1);
    }

    if((shmid = shmget((key_t)key, shsize, IPC_CREAT|0666))<0) {
        perror("shmget");
        exit(1);
    }

    if((shm = (char*)shmat(shmid, NULL, 0)) == (char*)-1) {
        perror("shmat");
        exit(1);
    }

    for(;;) {
        if(sem_trywait(mysem) == 0) {
            for(int i=0; i<100; i++) {
                printf("%d", (shm[i]));
            }

            putchar('\n');
            sem_post(mysem);
        }
        else {
            switch(errno) {
                case EAGAIN:
                    printf("EAGAIN\n");
                    break;
                case EDEADLK:
                    printf("EDEADLK\n");
                    break;
                case EINTR:
                    printf("EINTR\n");
                    break;
            }
        }

        usleep(100*1000);
    }
    

    sem_close(mysem);
    shmdt(shm);

    return 0;
}





하드디스크를 2개 쓰면서 하나는 윈도우, 다른 하나는 리눅스를 설치해 쓰고 있었다.


윈도우가 설치되어 있는 파티션을 포멧 푸 윈도우 재설치를 하고 나니 리눅스에서 다음과 같은 증상이 나타났다.


- 부팅 시 fsck가 실행됨

- $DISPLAY is not set or cannot connect to X server 라는 메시지가 출력되면서 X window가 실행되지 않음.


fsck의 대상 파티션을 보니 기존에 /etc/fstab에서 마운트하고 있던 윈도우쪽 파티션의 uuid가 바뀌어서 그런 것이었다.


 $ blkid


로 새로운 uuid를 확인하여 fstab파일을 고쳤더니 해결.




연관글  : http://tibyte.kr/242



테스트환경 : Debian linux(데비안), KDE


X window의 설정 메뉴에 없는 설정으로 화면 해상도를 변경하는 법.

설정에 1600x900 해상도가 없어서 직접 추가해보게 되었다.




1. cvt명령으로 원하는 해상도의 modeline을 계산한다.


$ cvt 1600 900





아래와 같은 결과가 출력된다.

이 출력 결과를 잠시 다른 곳에 복사해 둔다.


1600x900 59.95 Hz (CVT 1.44M9) hsync: 55.99 kHz; pclk: 118.25 MHz
Modeline "1600x900_60.00"  118.25  1600 1696 1856 2112  900 903 908 934 -hsync +vsync


modeline에서 각각의 수치는 video timing에 관련된 것이고 아래와 같다.

이름, pixelclock, hdisp, hsync-start, hsync-end, htotal, vdisp, vsync-start, vsync-end, vtotal

(관련 내용은 http://www.arachnoid.com/modelines/ 참고.)

(pixelclock는 초당 뿌려줄 수 있는 픽셀 수)






2. xrandr명령으로 현재 디스플레이 정보를 본다.


$ xrandr





아래 결과가 출력되는데,  xxxx connected 라는 부분이 있다.

디스플레이 장치마다 다르게 나오므로 이 부분의 이름을 기억해 둔다.


Screen 0: minimum 320 x 200, current 1360 x 768, maximum 8192 x 8192
xxxx connected primary 1360x768+0+0 (normal left inverted right x axis y axis) 345mm x 194mm
   1920x1080     59.93 +
   1680x1050     59.95    59.88 
   1600x1024     60.17 
   1400x1050     59.98 
   1280x1024     60.02 
   1440x900      59.89 
   1280x960      60.00 
   1360x768      59.80*   59.96 
   1152x864      60.00 
   1024x768      60.00 
   800x600       60.32    56.25 
   640x480       59.94 





3. xrandr의 newmode와 addmode로 추가한다.

newmode에서 1번에서 복사한 modeline수치들을 붙여넣는다.

(xxxx는 2번에서 확인한 이름)


$ xrandr --newmode "1600x900_60.00"  118.25  1600 1696 1856 2112  900 903 908 934 -hsync +vsync
$ xrandr --addmode xxxx 1600x900_60.00





다시 xrandr를 쳐서 확인해 보면 방금 설정한 해상도가 추가되어 있는 것을 볼 수 있다.

해상도를 적용하려면 xwindow의 디스플레이 설정 메뉴에서 설정해도 되고, 터미널에서도 할 수 있다.


$ xrandr --output xxxx --mode 1600x900_60.00






그러니 이 설정은 컴퓨터를 재부팅하면 초기화된다.

아래와 같이 쉘스크립트로 작성해 두고 xwindow시작 시 자동으로 실행되게 하면 편하다.

(x 시스템마다 다르므로 별도 설정)

#!/bin/sh
xrandr --newmode "1600x900_60.00"  118.25  1600 1696 1856 2112  900 903 908 934 -hsync +vsync
xrandr --addmode xxxx 1600x900_60.00
xrandr --output xxxx --mode 1600x900_60.00







  1. 비양 2015.10.24 15:29

    ㄷㄷ글쿤


노트북에 240GB짜리 디스크를 2개 장착하고, 논리 파티션을 총 3개로 하여

NTFS, NTFS, ext4로 쓰고 있다. NTFS 하나에는 windows를, ext4에는 리눅스 데비안을 설치한 상태.


리눅스로 부팅 시 윈도에서 포멧한 NTFS 디스크에 접근할 수 없다.

bash를 열고 다음과 같이 마운트해주어야 한다.


$ sudo  mount -t [디스크 포맷] [마운트할 디바이스 이름] [마운트 위치]


예시)

$ sudo mount -t ntfs /dev/sda1 /media/drive1


이 때 /dev/sda1과 같은 디바이스 이름은


$ sudo fdisk -l


명령을 통해 알 수 있다.



그런데 컴퓨터를 종료 후 재부팅할 때는 다시 마운트가 풀려 있다.

그래서 부팅 시 자동으로 마운트하도록 설정해야 하는데 

이것은 /etc/fstab 파일을 수정해서 할 수 있다.


fstab 파일을 수정하기 전에 먼저


$ sudo blkid


로 해당 드라이브의 UUID를 확인해 둔다.

그리고 슈퍼유저권한으로 fstab 파일을 편집기로 연다.


$ sudo vim /etc/fstab


기존에 드라이브가 하나 이상 추가되어 있을 것이므로 형식을 똑같이 맞춰 주면 된다.

여기서는 디스크식별자, 마운트위치, 포맷, 옵션, dump, 파일 시퀀스 체크 순.

이 항목들에 대한 자세한 내용은 여기(http://movenpick.tistory.com/34) 참고.


예시)

UUID=F4080E4463836387 /media/driveA ntfs default 0 0


※주의 : 잘못 추가시 부팅이 되지 않을 수도 있습니다.

※ UUID 대신 /deb/sda1 과 같은 형식도 가능.


저장하고 재부팅하면 마운트가 되어있는 것을 볼 수 있다!





+)
NTFS에서는 unix와 linux에서 사용하는 권한지정방식과 다른 방식으로 파일권한을 관리하기 때문에

모든 파일의 권한이 777로 나온다..




+ Recent posts