вторник, 29 ноября 2011 г.

Семафоры

В этой статье я опишу ещё один способ взаимодействия процессов.

Семафоры нужны чтобы предотвратить конфликты. Перед тем как воспользоваться доступом к ресурсу, процесс устанавливает семафор, чтобы занять место. Если семафор уже установлен другим процессом, текущий блокируется, пока ресурс не освободится.
Функции, которые мы будем использовать:
  • int semget(key_t KEY, int SEMS, int FLAGS);
Создает набор семафоров с ключем KEY и флагами FLAGS, SEMS - количество семафоров. Возвращает ID.
  • int semop(int ID, struct sembuf* SB, size_t SIZE);
 Позволяет совершать операции над набором семафоров с идентификатором ID. Структура sembuf:
struct sembuf {
   unsigned short int sem_num; /* номер семафора */
   short int sem_op; /* равен -1 если процесс собирается использовать ресурс, 1 - если ресурс свободен */
   short int sem_flg; /* флаги для операции над семафорами */
};
  • int semctl(int ID, int SNUM, int COMMAND, union semnum sem_arg);
Обычно служит для инициализации и удаления семафоров. SNUM - номер семафора. COMMAND может равняться SETALL(для инициализации) и IPC_RMID(для удаления).
union semnum {
   int val;
   struct semid_ds* buf;
   unsigned short* array;
};

Использование семафоров
 

/* Файл owner.c - запись данных в память */
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#include <sys/sem.h>

#define SHMEM_SIZE    4096
#define SH_MESSAGE    "test\n"

#define SEM_KEY        2012
#define SHM_KEY        2012

union semnum {
    int val;
    struct semid_ds * buf;
    unsigned short * array;
} sem_arg;


int
main(void)
{
    int shm_id, sem_id;
    char * shm_buf;
    int shm_size;
    struct shmid_ds ds;
    struct sembuf sb[1];
    unsigned short sem_vals[1];
    
    shm_id = shmget(SHM_KEY, SHMEM_SIZE,
            IPC_CREAT | IPC_EXCL | 0600);

    if(shm_id == -1)
    {
        fprintf(stderr, "shmget()\n");
        return 1;
    }

    sem_id = semget(SEM_KEY, 1,
            0600 | IPC_CREAT | IPC_EXCL);

    if(sem_id == -1)
    {
        fprintf(stderr, "semget()\n");
        return 1;
    }

    printf("Semaphore: %d\n", sem_id);
    sem_vals[0] = 1;
    sem_arg.array = sem_vals;

    if(semctl (sem_id, 0, SETALL, sem_arg) == -1)
    {
        fprintf(stderr, "semctl() error\n");
        return 1;
    }

    shm_buf = (char *) shmat(shm_id, NULL, 0);
    if (shm_buf == (char *) -1)
    {
        fprintf(stderr, "shmat() error\n");
        return 1;
    }

    shmctl(shm_id, IPC_STAT, &ds);
    
    shm_size = ds.shm_segsz;
    if(shm_size < strlen(SH_MESSAGE))
    {
        fprintf(stderr, "error: segsize=%d\n", shm_size);
        return 1;
    }
    
    strcpy(shm_buf, SH_MESSAGE);

    printf("ID: %d\n", shm_id);
    


    sb[0].sem_num = 0;
    sb[0].sem_flg = SEM_UNDO;

    sb[0].sem_op = -1;
    semop(sem_id, sb, 1);

    sb[0].sem_op = -1;
    semop(sem_id, sb, 1);

    semctl(sem_id, 1, IPC_RMID, sem_arg);
    shmdt(shm_buf);
    shmctl(shm_id, IPC_RMID, NULL);

    return 0;
}


/* Файл user.c - чтение данных из памяти */
#include <sys/shm.h>
#include <stdio.h>
#include <sys/sem.h>

#define SEM_KEY 2012
#define SHM_KEY 2012

int
main(int argc, char ** argv)
{
    int shm_id, sem_id;
    char * shm_buf;
    struct sembuf sb[1];

    shm_id = shmget(SHM_KEY, 1, 0600);
    if(shm_id == -1)
    {
        fprintf(stderr, "shmget() error\n");
        return 1;
    }
    
    sem_id = semget(SEM_KEY, 1, 0600);
    if(sem_id == -1)
    {
        fprintf(stderr, "semget() error\n");
        return 1;
    }

    shm_buf = (char *) shmat(shm_id, 0, 0);
    if(shm_buf == (char *) -1)
    {
        fprintf(stderr, "shmat() error\n");
        return 1;
    }

    printf("Message: %s\n", shm_buf);

    sb[0].sem_num = 0;
    sb[0].sem_flg = SEM_UNDO;

    sb[0].sem_op = 1;
    semop(sem_id, sb, 1);
    
    shmdt(shm_buf);

    return 0;
}
Семафоры - owner

Семафоры - user

Функции, которые не описанны в этой статье, описаны в статье  Использование общей памяти

Комментариев нет:

Отправить комментарий