[태그:] linux

  • memory based semaphore, unix network programming p241

    이름있는 세마포어 말고 메모리에 올려 사용하는 방법도 있다. 책은 sem_init(…, 두번째 arg,…)에서 두번째 입력하는 숫자를 thread에서 공유할 거면 0, 프로세스간 할거면 1로 하라고 한다. 1로 하여 thread도 잘 된다.

    named semaphore는 포인터를 선언했고 파일에 영역을 만들었다. 이와 다르게 직접 데이터를 선언하고 주소로 넘겨줘야 한다.

    ipcs로 보일 법 한데, 안 보인다. 무엇이 잘못되었는지 모르겠다.

    /* include main */
    #include <pthread.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <semaphore.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #define	NBUFF	 10
    #define	SEM_MUTEX	"mutex"	 	/* these are args to px_ipc_name() */
    #define	SEM_NEMPTY	"empty"
    #define	SEM_NSTORED	"nstored"
    
    int		nitems;					/* read-only by producer and consumer */
    struct {	/* data shared by producer and consumer */
      int	buff[NBUFF];
      //포인터 대신 세마포어로 변경.
      //sem_t	*mutex, *nempty, *nstored;
      sem_t	mutex, nempty, nstored;		/* semaphores, not pointers */
    
    } shared;
    
    void	*produce(void *), *consume(void *);
    
    int
    main(int argc, char **argv)
    {
    	pthread_t	tid_produce, tid_consume;
    
    	if (argc != 2)
    		perror("usage: prodcons1 <#items>");
    	nitems = atoi(argv[1]);
    		/* 4create three semaphores */
    	//memory based로 변경.
    	/*
    	shared.mutex = sem_open(SEM_MUTEX, O_CREAT | O_EXCL,
    							0660, 1);
    	shared.nempty = sem_open(SEM_NEMPTY, O_CREAT | O_EXCL,
    							 0660, NBUFF);
    	shared.nstored = sem_open(SEM_NSTORED, O_CREAT | O_EXCL,
    							  0660, 0);
    							  */
    
    
    	//두번째 파라미터를 0으로 설정해야 thread간 전달.
    	//sem_init(&shared.mutex, 1, 1) 설정해도 잘 됨..
    
    	sem_init(&shared.mutex, 0, 1);
    	sem_init(&shared.nempty, 0, NBUFF);
    	sem_init(&shared.nstored, 0, 0);
    
    
    		/* 4create one producer thread and one consumer thread */
    	//pthread_setconcurrency(2);
    	//pthread_setconcurrency();
    	pthread_create(&tid_produce, NULL, produce, NULL);
    	pthread_create(&tid_consume, NULL, consume, NULL);
    
    		/* 4wait for the two threads */
    	pthread_join(tid_produce, NULL);
    	pthread_join(tid_consume, NULL);
    
    		/* 4remove the semaphores */
    	//메모리 베이스로 변경.
    	/*
    	sem_unlink(SEM_MUTEX);
    	sem_unlink(SEM_NEMPTY);
    	sem_unlink(SEM_NSTORED);
    	*/
    
    
    	//ipcs로 확인하기위해 대기
    	sleep(10);
    
    	sem_destroy(&shared.mutex);
    	sem_destroy(&shared.nempty);
    	sem_destroy(&shared.nstored);
    
    	exit(0);
    }
    /* end main */
    
    /* include prodcons */
    void *
    produce(void *arg)
    {
    	int		i;
    
    	for (i = 0; i < nitems; i++) {
    
    		sem_wait(&shared.nempty);	/* wait for at least 1 empty slot */
    		sem_wait(&shared.mutex);
    
    		shared.buff[i % NBUFF] = i;	/* store i into circular buffer */
    		sem_post(&shared.mutex);
    		sem_post(&shared.nstored);	/* 1 more stored item */
    
    
    	}
    	return(NULL);
    }
    
    void *
    consume(void *arg)
    {
    	int		i;
    	int tmpnempty, tmpmutex, tmpnstored;
    
    	for (i = 0; i < nitems; i++) {
    
    
    		sem_wait(&shared.nstored);		/* wait for at least 1 stored item */
    		sem_wait(&shared.mutex);
    
    
    		if (shared.buff[i % NBUFF] = i)
    			printf("buff[%d] = %d\n", i, shared.buff[i % NBUFF]);
    		sem_post(&shared.mutex);
    		sem_post(&shared.nempty);		/* 1 more empty slot */
    
    	}
    	return(NULL);
    }
    /* end prodcons */
    
    pi@raspberrypi:~/Project/cCode/IPC $ ipcs
    
    ------ Message Queues --------
    key        msqid      owner      perms      used-bytes   messages    
    
    ------ Shared Memory Segments --------
    key        shmid      owner      perms      bytes      nattch     status      
    
    ------ Semaphore Arrays --------
    key        semid      owner      perms      nsems     
    
    

    ipcs는 system V 기능이라 posix semaphore는 해당하지 않는다. 보이지 않음이 당연하다.

  • unix network programming, vol 2

    unix network programming, vol 2

    isbn:  9780130810816

    대학교 vol 1을 읽었고 너무 오래된 시스템이라 잘 실행안됬음을 기억했다. 가벼운 마음으로 IPC를 알아보려 찾았는데, 600페이지 책 한 권을 읽고 있다. 책도 나온지 너무 오래되어 웬만하면 하나 사려고 했는데, 종이책으로만 있다!! 인터넷에서 잘 찾았다.

    아래 그림은 개요장에 있는데 이 그림으로 길고 지루한 길을 쉽게 갈 수 있다. 예상한 바와 같이 파일로 정보를 공유함은 너무 급이 떨어진다. 고급지게 메세지 큐, 파이프, 세마포어로 가자고!!

    이런 책을 찾지 않고, 스스로 고민하고 있으면 낮은 성과를 많은 시간을 들여 얻는다. 내가 생각했었고 더 깊은 내용까지 설명한다. 내가 무엇을 모르는지 알고, 어디 있는지 찾는 능력이 중요하다.

    근데 너무 길다. System V는 먼지 모르겠으나 오래되어 포기했고 POSIX만 찾아 보는데도 쉽게 못나간다. 너무 깊게 들어가는 기분이다.

    https://www.joinc.co.kr/w/Site/system_programing/Book_LSP/ch08_IPC
  • semaphore p223 ~ p238

    name semaphore는 /dev/shm에 저장된다. 이름을 엄한 /tmp/xxx 이런 식으로 만들면 세마포어를 만들 수 없다. segment error로 죽는다. 책에서는 /tmp/로 넣어도 잘 동작해서 확인하는데 오래 걸렸다.

    디버그 하다 중간에 멈추면 /dev/shm에 sem*로 파일을 지울 수 없어 다음 실행에 세마포어를 받을 수 없다. 처음 시작 전 자기 이름으로 된 세마포어 있으면 지워야 한다.

    thread를 돌리면 미친 race condition이 피곤하게 한다. 참 헷갈리는데, 자주보면 익숙해 지겠지. thread를 돌리면 순서는 이제 별 의미 없는 듯 하다. sem_post하는 즉시 자기 thread를 실행하는게 아니라 다른 thread로 가서 프로그램을 실행한다. wait로 thread 이후 행을 잘 막는 게 핵심인 듯 하다.

    /* include main */
    #include <pthread.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <semaphore.h>
    #include <sys/stat.h>
    #define	NBUFF	 10
    #define	SEM_MUTEX	"mutex"	 	/* these are args to px_ipc_name() */
    #define	SEM_NEMPTY	"empty"
    #define	SEM_NSTORED	"nstored"
    
    int		nitems;					/* read-only by producer and consumer */
    struct {	/* data shared by producer and consumer */
      int	buff[NBUFF];
      sem_t	*mutex, *nempty, *nstored;
    } shared;
    
    void	*produce(void *), *consume(void *);
    
    int
    main(int argc, char **argv)
    {
    	pthread_t	tid_produce, tid_consume;
    	int errno;
    	
    
    	if (argc != 2)
    		perror("usage: prodcons1 <#items>");
    	nitems = atoi(argv[1]);
    		/* 4create three semaphores */
    	shared.mutex = sem_open(SEM_MUTEX, O_CREAT | O_EXCL,
    							0660, 1);
    	shared.nempty = sem_open(SEM_NEMPTY, O_CREAT | O_EXCL,
    							 0660, NBUFF);
    	shared.nstored = sem_open(SEM_NSTORED, O_CREAT | O_EXCL,
    							  0660, 0);
    
    		/* 4create one producer thread and one consumer thread */
    	//pthread_setconcurrency(2);
    	//pthread_setconcurrency();
    	pthread_create(&tid_produce, NULL, produce, NULL);
    	pthread_create(&tid_consume, NULL, consume, NULL);
    
    		/* 4wait for the two threads */
    	pthread_join(tid_produce, NULL);
    	pthread_join(tid_consume, NULL);
    
    		/* 4remove the semaphores */
    	sem_unlink(SEM_MUTEX);
    	sem_unlink(SEM_NEMPTY);
    	sem_unlink(SEM_NSTORED);
    	exit(0);
    }
    /* end main */
    
    /* include prodcons */
    void *
    produce(void *arg)
    {
    	int		i;
    	int tmpnempty, tmpmutex, tmpnstored;
    
    	for (i = 0; i < nitems; i++) {
    
    
    		//value check
    		//sem_getvalue(shared.nempty, &tmpnempty);
    		//sem_getvalue(shared.nstored, &tmpnstored);
    		//sem_getvalue(shared.mutex, &tmpmutex);
    
    		sem_wait(shared.nempty);	/* wait for at least 1 empty slot */
    		sem_wait(shared.mutex);
    
    		//value check
    		//sem_getvalue(shared.nempty, &tmpnempty);
    		//sem_getvalue(shared.nstored, &tmpnstored);
    		//sem_getvalue(shared.mutex, &tmpmutex);
    
    
    
    		shared.buff[i % NBUFF] = i;	/* store i into circular buffer */
    		sem_post(shared.mutex);
    		sem_post(shared.nstored);	/* 1 more stored item */
    		//value check
    		//sem_getvalue(shared.nempty, &tmpnempty);
    		//sem_getvalue(shared.nstored, &tmpnstored);
    		//sem_getvalue(shared.mutex, &tmpmutex);
    
    
    	}
    	return(NULL);
    }
    
    void *
    consume(void *arg)
    {
    	int		i;
    	int tmpnempty, tmpmutex, tmpnstored;
    
    	for (i = 0; i < nitems; i++) {
    		//value check
    		//sem_getvalue(shared.nempty, &tmpnempty);
    		//sem_getvalue(shared.mutex, &tmpmutex);
    		//sem_getvalue(shared.nstored, &tmpnstored);
    
    
    		sem_wait(shared.nstored);		/* wait for at least 1 stored item */
    		sem_wait(shared.mutex);
    		//value check
    		//sem_getvalue(shared.nempty, &tmpnempty);
    		//sem_getvalue(shared.mutex, &tmpmutex);
    		//sem_getvalue(shared.nstored, &tmpnstored);
    
    
    		if (shared.buff[i % NBUFF] = i)
    			printf("buff[%d] = %d\n", i, shared.buff[i % NBUFF]);
    		sem_post(shared.mutex);
    		sem_post(shared.nempty);		/* 1 more empty slot */
    		//value check
    		//sem_getvalue(shared.nempty, &tmpnempty);
    		//sem_getvalue(shared.mutex, &tmpmutex);
    		//sem_getvalue(shared.nstored, &tmpnstored);
    
    
    	}
    	return(NULL);
    }
    /* end prodcons */
    
    pi@raspberrypi:~/Project/cCode/IPC $ gdb --args ./a.out  3
    GNU gdb (Raspbian 8.2.1-2) 8.2.1
    Copyright (C) 2018 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.
    Type "show copying" and "show warranty" for details.
    This GDB was configured as "arm-linux-gnueabihf".
    Type "show configuration" for configuration details.
    For bug reporting instructions, please see:
    <http://www.gnu.org/software/gdb/bugs/>.
    Find the GDB manual and other documentation resources online at:
        <http://www.gnu.org/software/gdb/documentation/>.
    
    For help, type "help".
    Type "apropos word" to search for commands related to "word"...
    Reading symbols from ./a.out...done.
    ...
    
    (gdb) info b
    Num     Type           Disp Enb Address    What
    1       breakpoint     keep y   0x000107b4 in produce at semaphore.c:72
    	breakpoint already hit 3 times
    2       breakpoint     keep y   0x00010884 in consume at semaphore.c:108
    	breakpoint already hit 3 times
    (gdb) r
    Starting program: /home/pi/Project/cCode/IPC/a.out 3
    [Thread debugging using libthread_db enabled]
    Using host libthread_db library "/lib/arm-linux-gnueabihf/libthread_db.so.1".
    [New Thread 0xb6e31460 (LWP 2842)]
    [New Thread 0xb6630460 (LWP 2843)]
    [Switching to Thread 0xb6e31460 (LWP 2842)]
    
    Thread 2 "a.out" hit Breakpoint 1, produce (arg=0x0) at semaphore.c:72
    72			sem_wait(shared.nempty);	/* wait for at least 1 empty slot */
    1: shared = {buff = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, mutex = 0xb6ff8000, 
      nempty = 0xb6ff7000, nstored = 0xb6ff6000}
    2: *shared.nempty = {
      __size = "\024\000\000\000\200\000\000\000\000\000\000\000\000\000\000", 
      __align = 20}
    3: *shared.nstored = {
      __size = "\000\000\000\000\200\000\000\000\000\000\000\000\000\000\000", 
      __align = 0}
    4: *shared.mutex = {
      __size = "\002\000\000\000\200\000\000\000\000\000\000\000\000\000\000", 
      __align = 2}
    (gdb) c
    Continuing.
    [Switching to Thread 0xb6630460 (LWP 2843)]
    
    Thread 3 "a.out" hit Breakpoint 2, consume (arg=0x0) at semaphore.c:108
    108			sem_wait(shared.nstored);		/* wait for at least 1 stored item */
    1: shared = {buff = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, mutex = 0xb6ff8000, 
      nempty = 0xb6ff7000, nstored = 0xb6ff6000}
    2: *shared.nempty = {
      __size = "\024\000\000\000\200\000\000\000\000\000\000\000\000\000\000", 
      __align = 20}
    3: *shared.nstored = {
      __size = "\000\000\000\000\200\000\000\000\000\000\000\000\000\000\000", 
      __align = 0}
    4: *shared.mutex = {
      __size = "\002\000\000\000\200\000\000\000\000\000\000\000\000\000\000", 
      __align = 2}
    (gdb) c
    Continuing.
    [Switching to Thread 0xb6e31460 (LWP 2842)]
    
    Thread 2 "a.out" hit Breakpoint 1, produce (arg=0x0) at semaphore.c:72
    72			sem_wait(shared.nempty);	/* wait for at least 1 empty slot */
    1: shared = {buff = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, mutex = 0xb6ff8000, 
      nempty = 0xb6ff7000, nstored = 0xb6ff6000}
    2: *shared.nempty = {
      __size = "\022\000\000\000\200\000\000\000\000\000\000\000\000\000\000", 
      __align = 18}
    3: *shared.nstored = {
      __size = "\002\000\000\000\200\000\000\000\000\000\000\000\000\000\000", 
      __align = 2}
    4: *shared.mutex = {
      __size = "\002\000\000\000\200\000\000\000\000\000\000\000\000\000\000", 
      __align = 2}
    (gdb) c
    Continuing.
    [Switching to Thread 0xb6630460 (LWP 2843)]
    
    Thread 3 "a.out" hit Breakpoint 2, consume (arg=0x0) at semaphore.c:108
    108			sem_wait(shared.nstored);		/* wait for at least 1 stored item */
    1: shared = {buff = {0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, mutex = 0xb6ff8000, 
      nempty = 0xb6ff7000, nstored = 0xb6ff6000}
    2: *shared.nempty = {
      __size = "\022\000\000\000\200\000\000\000\000\000\000\000\000\000\000", 
      __align = 18}
    3: *shared.nstored = {
      __size = "\002\000\000\000\200\000\000\000\000\000\000\000\000\000\000", 
      __align = 2}
    4: *shared.mutex = {
      __size = "\002\000\000\000\200\000\000\000\000\000\000\000\000\000\000", 
      __align = 2}
    (gdb) c
    Continuing.
    [Switching to Thread 0xb6e31460 (LWP 2842)]
    
    Thread 2 "a.out" hit Breakpoint 1, produce (arg=0x0) at semaphore.c:72
    72			sem_wait(shared.nempty);	/* wait for at least 1 empty slot */
    1: shared = {buff = {0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, mutex = 0xb6ff8000, 
      nempty = 0xb6ff7000, nstored = 0xb6ff6000}
    2: *shared.nempty = {
      __size = "\022\000\000\000\200\000\000\000\000\000\000\000\000\000\000", 
      __align = 18}
    3: *shared.nstored = {
      __size = "\002\000\000\000\200\000\000\000\000\000\000\000\000\000\000", 
      __align = 2}
    4: *shared.mutex = {
      __size = "\002\000\000\000\200\000\000\000\000\000\000\000\000\000\000", 
      __align = 2}
    (gdb) c
    Continuing.
    buff[1] = 1
    [Thread 0xb6e31460 (LWP 2842) exited]
    [Switching to Thread 0xb6630460 (LWP 2843)]
    
    Thread 3 "a.out" hit Breakpoint 2, consume (arg=0x0) at semaphore.c:108
    108			sem_wait(shared.nstored);		/* wait for at least 1 stored item */
    1: shared = {buff = {0, 1, 2, 0, 0, 0, 0, 0, 0, 0}, mutex = 0xb6ff8000, 
      nempty = 0xb6ff7000, nstored = 0xb6ff6000}
    2: *shared.nempty = {
      __size = "\022\000\000\000\200\000\000\000\000\000\000\000\000\000\000", 
      __align = 18}
    3: *shared.nstored = {
      __size = "\002\000\000\000\200\000\000\000\000\000\000\000\000\000\000", 
      __align = 2}
    4: *shared.mutex = {
      __size = "\002\000\000\000\200\000\000\000\000\000\000\000\000\000\000", 
      __align = 2}
    (gdb) c
    Continuing.
    buff[2] = 2
    [Thread 0xb6ffa070 (LWP 2841) exited]
    [Inferior 1 (process 2841) exited normally]
    (gdb) 
    
    https://unix.stackexchange.com/questions/275650/where-is-a-named-semaphore-stored
  • sync, mutex. unix network programming p161

    다시 thread로 돌아왔다.

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <pthread.h>
    #define	MAXNITEMS 		1000000
    #define	MAXNTHREADS			100
    #define MIN(X,Y) ((X)<(Y) ? (X) : (Y))
    
    
    
    //gcc -lpthread 옵션으로 컴파일.
    int		nitems;			/* read-only by producer and consumer */
    
    
    //shared를 초기화 하는데,
    //맨 처음에 mutext가 있음.
    //나머지는 0으로 초기화됨..
    struct {
      pthread_mutex_t	mutex;
      int	buff[MAXNITEMS];
      int	nput;
      int	nval;
    } shared = { PTHREAD_MUTEX_INITIALIZER };
    
    void	*produce(void *), *consume(void *);
    
    
    int
    main(int argc, char **argv)
    {
    	int			i, nthreads, count[MAXNTHREADS];
    	pthread_t	tid_produce[MAXNTHREADS], tid_consume;
    	//앞에서부터 초기화.
    	struct test {
    		int no1;
    		int no2;
    	} teststruct = {10};
    
    	if (argc != 3)
    		perror("usage: prodcons2 <#items> <#threads>");
    	nitems = MIN(atoi(argv[1]), MAXNITEMS);
    	nthreads = MIN(atoi(argv[2]), MAXNTHREADS);
    
    	//pthread_setconcurrency();
    		/* 4start all the producer threads */
    	for (i = 0; i < nthreads; i++) {
    		count[i] = 0;
    		pthread_create(&tid_produce[i], NULL, produce, &count[i]);
    	}
    
    		/* 4wait for all the producer threads */
    	for (i = 0; i < nthreads; i++) {
    		pthread_join(tid_produce[i], NULL);
    		printf("count[%d] = %d\n", i, count[i]);	
    	}
    
    		/* 4start, then wait for the consumer thread */
    	pthread_create(&tid_consume, NULL, consume, NULL);
    	pthread_join(tid_consume, NULL);
    
    	exit(0);
    }
    /* end main */
    
    /* include producer */
    void *
    produce(void *arg)
    {
    	for ( ; ; ) {
    		pthread_mutex_lock(&shared.mutex);
    		if (shared.nput >= nitems) {
    			pthread_mutex_unlock(&shared.mutex);
    			return(NULL);		/* array is full, we're done */
    		}
    		shared.buff[shared.nput] = shared.nval;
    		shared.nput++;
    		shared.nval++;
    		pthread_mutex_unlock(&shared.mutex);
    		*((int *) arg) += 1;
    	}
    }
    
    void *
    consume(void *arg)
    {
    	int		i;
    
    	for (i = 0; i < nitems; i++) {
    		if (shared.buff[i] != i)
    			printf("buff[%d] = %d\n", i, shared.buff[i]);
    	}
    	return(NULL);
    }
    /* end producer */
    
  • message queue, unix network programming 75p ~ 90p

    fifo는 먼저 들어온 순서로 동작하지만, message queue는 빠른 우선순위로 동작한다.

    signal handler를 정의하여 사용할 수도 있다. message noty는 queue가 비어있을 경우 한번 동작한다. queue가 차 있다면 signal을 무시한다. 한 번 사용하면 다시 시그널을 등록해야 한다.

    pi@raspberrypi:~/Project/cCode/IPC $ cat mesquereceive.c 
    //message que header
    #include <unistd.h>
    #include <stdio.h>
    #include <fcntl.h>
    #include <sys/stat.h>
    #include <mqueue.h>
    #include <signal.h>
    #define MAX_SIZE 100
    
    //signal 처리하기 위한 hanlder
    static void sig_usr1(int mysig);
    
    struct sigevent sigev;
    //signal hanlder로 사용하려고 global로 등록.
    mqd_t	mqd;
    struct mq_attr attr;
    int priorecv;
    char buff[100];
    
    int main(){
    	int		c, flags;
    	char const *quename="/tmp_message";
    	char messageptr[50]= "this is a test.";
    	//메세지 큐 초기화
    	attr.mq_flags = 0;
        attr.mq_maxmsg = 10;
        attr.mq_msgsize = MAX_SIZE;
        attr.mq_curmsgs = 0;
    
    
    	//message를 넣기전에 mq_notify 정의
    	signal(SIGUSR1, sig_usr1);
    	sigev.sigev_notify = SIGEV_SIGNAL;
    	sigev.sigev_signo = SIGUSR1;
    	mq_notify(mqd, &sigev);
    
    	flags = O_RDWR | O_CREAT;
    	//gcc 컴파일시 gcc mesque.c -lrt
    	//로 해야 컴파일 됨.
    	mqd = mq_open(quename, flags, 0666, &attr);
    	size_t len = sizeof(messageptr);
    	//mq_send(mqd, messageptr, len, 10);
    	//sleep(1);
    
    
    	//넣은 메세지를 확인
    	//mq_receive(mqd, buff, attr.mq_msgsize, &priorecv);
    	//printf("받은 메세지는\n %s를 %d 우선 순위로\n", buff, priorecv);
    	//mq_receive(mqd, buff, attr.mq_msgsize, &priorecv);
    	//printf("받은 메세지는\n %s를 %d 우선 순위로\n", buff, priorecv);
    	for(;;)
    		pause();
    	mq_close(mqd);
    	return 0;
    }
    
    void sig_usr1(int mysig){
    	//signal hanlder로 message receive..
    
    	//한번 사용한 noty는 다시 등록.
    	mq_notify(mqd, &sigev);
    	mq_receive(mqd, buff, attr.mq_msgsize, &priorecv);
    	printf("받은 메세지는\n %s를 %d 우선 순위로\n", buff, priorecv);
    	return;
    
    
    
    }
    
    pi@raspberrypi:~/Project/cCode/IPC $ cat mesquesender.c 
    //message que header
    #include <unistd.h>
    #include <stdio.h>
    #include <fcntl.h>
    #include <sys/stat.h>
    #include <mqueue.h>
    #include <stdlib.h>
    #include <signal.h>
    #define MAX_SIZE 100
    
    
    mqd_t	mqd;
    struct mq_attr attr;
    int priorecv;
    char buff[100];
    
    int main(int argc, char** argv){
    	int		c, flags;
    	int prio;
    	char const *quename="/tmp_message";
    	char messageptr[50]= "this is a test.";
    	//메세지 큐 초기화
    	attr.mq_flags = 0;
        attr.mq_maxmsg = 10;
        attr.mq_msgsize = MAX_SIZE;
        attr.mq_curmsgs = 0;
    
    	flags = O_RDWR | O_CREAT;
    	//gcc 컴파일시 gcc mesque.c -lrt
    	//로 해야 컴파일 됨.
    	mqd = mq_open(quename, flags, 0666, &attr);
    	size_t len = sizeof(messageptr);
    
    	prio = atoi(argv[1]);
    	mq_send(mqd, messageptr, len, prio);
    	mq_close(mqd);
    	return 0;
    }
    
    pi@raspberrypi:~/Project/cCode/IPC $ mv mesque.c mesquereceive.c
    pi@raspberrypi:~/Project/cCode/IPC $ gcc -lrt mesquereceive.c -o recv
    pi@raspberrypi:~/Project/cCode/IPC $ gcc -lrt mesquesender.c -o send
    pi@raspberrypi:~/Project/cCode/IPC $ cat /dev/mqueue/tmp_message 
    QSIZE:0          NOTIFY:0     SIGNO:0     NOTIFY_PID:0     
    pi@raspberrypi:~/Project/cCode/IPC $ ./send 
    세그멘테이션 오류
    pi@raspberrypi:~/Project/cCode/IPC $ ./send 10
    pi@raspberrypi:~/Project/cCode/IPC $ ./send 20
    pi@raspberrypi:~/Project/cCode/IPC $ cat /dev/mqueue/tmp_message 
    QSIZE:100        NOTIFY:0     SIGNO:0     NOTIFY_PID:0     
    pi@raspberrypi:~/Project/cCode/IPC $ ./send 100
    pi@raspberrypi:~/Project/cCode/IPC $ ./recv 
    ^Z
    [1]+  Stopped                 ./recv
    pi@raspberrypi:~/Project/cCode/IPC $ bg
    [1]+ ./recv &
    pi@raspberrypi:~/Project/cCode/IPC $ cat /dev/mqueue/tmp_message 
    QSIZE:150        NOTIFY:0     SIGNO:0     NOTIFY_PID:0     
    pi@raspberrypi:~/Project/cCode/IPC $ ./send 15
    pi@raspberrypi:~/Project/cCode/IPC $ bg
    -bash: bg: job 1 already in background
    pi@raspberrypi:~/Project/cCode/IPC $ jobs
    [1]+  Running                 ./recv &
    pi@raspberrypi:~/Project/cCode/IPC $ ./send 20
    pi@raspberrypi:~/Project/cCode/IPC $ pidof recv 
    16120
    pi@raspberrypi:~/Project/cCode/IPC $ pidof recv |xargs kill -10
    받은 메세지는
     this is a test.를 100 우선 순위로
    pi@raspberrypi:~/Project/cCode/IPC $ pidof recv |xargs kill -10
    받은 메세지는
     this is a test.를 20 우선 순위로
    pi@raspberrypi:~/Project/cCode/IPC $ pidof recv |xargs kill -10
    받은 메세지는
     this is a test.를 20 우선 순위로
    pi@raspberrypi:~/Project/cCode/IPC $ pidof recv |xargs kill -10
    받은 메세지는
     this is a test.를 15 우선 순위로
    pi@raspberrypi:~/Project/cCode/IPC $ pidof recv |xargs kill -10
    받은 메세지는
     this is a test.를 10 우선 순위로
    pi@raspberrypi:~/Project/cCode/IPC $ pidof recv |xargs kill -10
    pi@raspberrypi:~/Project/cCode/IPC $ ./send 100
    받은 메세지는
     this is a test.를 100 우선 순위로
    pi@raspberrypi:~/Project/cCode/IPC $ cat /dev/mqueue/tmp_message 
    QSIZE:0          NOTIFY:0     SIGNO:10    NOTIFY_PID:16120 
    pi@raspberrypi:~/Project/cCode/IPC $ ./send 10
    받은 메세지는
     this is a test.를 10 우선 순위로
    pi@raspberrypi:~/Project/cCode/IPC $ cat /dev/mqueue/tmp_message 
    QSIZE:0          NOTIFY:0     SIGNO:10    NOTIFY_PID:16120 
    pi@raspberrypi:~/Project/cCode/IPC $ 
    
    https://www.joinc.co.kr/w/Site/system_programing/IPC/MessageQueue

    gcc 기본 컴파일하면 에러를 본다. 옵션 넣어야 한다. -lrt.

    https://stackoverflow.com/questions/19964206/weird-posix-message-queue-linking-issue-sometimes-it-doesnt-link-correctly