세마포어를 이용한 IPC

Sat, Mar 20 2021 15:43:56

2021년 4월 22일에 업데이트 하였습니다.

다음 소스코드는 여러 개의 클라이언트가 서버에 접속해서 이벤트를 보내며, 서버는 이벤트를 순차적으로 처리합니다. 유닉스 소켓보다 빠른 공유 메모리를 사용하였으며 동기적으로 처리하기 위해 세마포어를 활용합니다. 이 구현이 유닉스 소켓을 사용한 것보다 실제로 빠른지는 테스트하지 않았습니다.

server.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <semaphore.h>
#include <string.h>

typedef struct {
  sem_t  sem_client;
  sem_t  sem_server;
  time_t time;
  pid_t  pid;
} SharedData;

int main (int argc, char **argv)
{
  int fd;
  SharedData *data = NULL;
  const size_t len = sizeof (SharedData);
  /* struct timespec abstime; */
  /* abstime.tv_nsec = 0; */

  fd = shm_open ("/tmp/example", O_RDWR | O_CREAT, 0600);

  if ((fd < 0) ||
      (ftruncate (fd, len) < 0))
    goto finally;

  data = mmap (0, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  sem_init (&data->sem_client, 1, 0);
  sem_init (&data->sem_server, 1, 1);

  while (1)
  {
    int retval;

    retval = sem_wait (&data->sem_client);
    /* abstime.tv_sec = time (NULL) + 1; */
    /* retval = sem_timedwait (&data->sem_client, &abstime); */

    if (retval == 0)
    {
      printf ("%d: %ld\n", data->pid, data->time);
    }
    else
    {
      printf ("error: %s\n", strerror (errno));
    }

    int sval;
    sem_getvalue (&data->sem_server, &sval);

    if (sval == 0)
      sem_post (&data->sem_server);

    puts ("continue");
  }

  finally:

  if (data)
  {
    sem_destroy (&data->sem_client);
    sem_destroy (&data->sem_server);
    munmap (data, len);
  }

  if (fd > 0)
    close (fd);

  if (errno)
    perror ("");

  shm_unlink ("/tmp/example");

  return errno;
}

client.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <semaphore.h>

typedef struct {
  sem_t  sem_client;
  sem_t  sem_server;
  time_t time;
  pid_t  pid;
} SharedData;

int main (int argc, char **argv)
{
  int fd;
  SharedData *data = NULL;
  const size_t len = sizeof (SharedData);

  fd = shm_open ("/tmp/example", O_RDWR, 0600);

  if ((fd < 0) ||
      (ftruncate (fd, len) < 0))
    goto finally;

  data = mmap (0, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

  while (1)
  {
    sem_wait (&data->sem_server);
    data->time = time (NULL);
    data->pid  = getpid ();
    int sval;
    sem_getvalue (&data->sem_client, &sval);

    if (sval == 0)
      sem_post (&data->sem_client);

    printf ("%d, %ld\n", data->pid, data->time);
    sleep (1);
  }

  finally:

  if (data)
    munmap (data, len);

  if (fd > 0)
    close (fd);

  if (errno)
    perror ("");

  return errno;
}

Makefile

all: client.c server.c Makefile
	cc -Wall -Werror -o client client.c
	cc -Wall -Werror -o server server.c