semafory_ipc.c

/*
 * plik ma na celu prezentację podstawowych zagadnień z programowania w języku C / C++
 * prezentuje korzystanie z komunikacji międzyprocesowej poprzez SystemV IPC (svipc):
 * semafory pamięć współdzielona i kolejki komunikatów
 *
 * warto zajrzeć też na: http://rainbow.mimuw.edu.pl/~mengel/jpp/sem/
 *
 */
 
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>

#include <stdio.h>
#include <errno.h>
#include <string.h>

// z manula dotyczacego semctl:
  #if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
  /* union semun jest zdefiniowana w <sys/sem.h> */
  #else
  /* dla zgodnoci z X/OPEN musimy sami sobie zdefiniować */
  union semun {
  int val;                  /* wartość dla SETVAL */
  struct semid_ds *buf;     /* bufor dla IPC_STAT i IPC_SET */
  unsigned short *array;    /* tablica dla GETALL i SETALL */
                            /* Część specyficzna dla Linuksa: */
  struct seminfo *__buf;    /* bufor dla IPC_INFO */
  };
  #endif


int main(int argc, char *argv[]) {
  int pid=getpid();
  
  /// nazwa i klucz semafora
  const char * nazwa_semafora = "Moje_ICP";
  key_t klucz=0;
  int i;
  for (i=0; nazwa_semafora[i]!=0; i++)
    klucz += nazwa_semafora[i];
  // w zasadzie to do tworzenia klucza należałoby użyć funkcji ftok(char *pathname, char proj_id);
  
  printf("%d: uzyskałem klucz: %x\n", pid, klucz);
  
  
/** SEMAFORY **/
  
  
  /// tworzymy zestaw semaforów bądź uzyskujemy dostęp do istniejącego
  // tworzymy semafor gdy nie istnieje
  int identyfikator_zestawu_semaforow = semget (klucz, 1, 0640|IPC_CREAT|IPC_EXCL);
    // pierwszym argumentem jest dluga liczba calkowita pelniaca funkcje nazwy
    // zestawu semaforow (zamiast niej mozna podac IPC_PRIVATE wtedy jednak
    // zestawu możemy używać tylko w tym i w potomnych procesach)
    // dugim jest liczba semaforow w zestawie
    // trzecim są flagi (okreslajace prawa dostepu do zestawu semaforow
    // (jak do pliku) oraz sposob otwarcia (IPC_CREAT - utworzenie gdy nie ma
    // lub otwarcie gdy jest, IPC_CREAT | IPC_EXCL - utworzenie gdy nie ma,
    // błąd gdy jest)
  if (identyfikator_zestawu_semaforow != -1) {
  // jeżeli się udało nadajemy mu wartość początkową
    printf("%d: utworzyłem zestaw semaforów o identyfikatorze: %i\n", pid, identyfikator_zestawu_semaforow);
    union semun ctl_arg;
    ctl_arg.val=1;
    semctl (identyfikator_zestawu_semaforow, 0, SETVAL, ctl_arg);
      // drugim argumentem jest numer semafora
      // trzecim argumentaem jest polecenie
      // (SETVAL = ustaw na wartość z ctl_arg.val, więcej man 2 semctl)
      // trzecim jest union semun w tym wypadku interesuje nas pole val
  } else if (errno == EEXIST) {
  // w przeciwnym razie korzystamy z istniejącego
    identyfikator_zestawu_semaforow = semget (klucz, 1, 0640);
    printf("%d: uzyskałem dostęp do semafora o identyfikatorze: %i\n", pid, identyfikator_zestawu_semaforow);
  } else {
    printf("BŁĄD: %i", errno);
    return -1;
  }

  /// uzywanie semaforów
  // - sprawdzamy czy jest zezwolenie (ewentualnie czekamy na nie) i ustawiamy blokadę
  
  // tablica struktur opisujących operacje
  struct sembuf operacje [1];
  // pierwsza operacja
  (operacje[0]).sem_num = 0; // pierwszy, czyli zerowy ;-) semafor
  (operacje[0]).sem_op = -1; // gdy wartość semafora >= |-1| dodaj do wartości
                             // semafora -1 i kontynuuj, inaczej czekaj ...
  (operacje[0]).sem_flg = SEM_UNDO; // możliwe są:
  //   SEM_UNDO (zmiana stanu semafora cofnieta w momęcie zakończenia procesu) i
  //   IPC_NOWAIT (gdy nie może być wykonana natychmiast konczy semop z błędem)
  
  printf("%d: oczekiwanie na semafor\n", pid);
  
  // wykonanie operacji
  semop (identyfikator_zestawu_semaforow, operacje, 1);
    // trzecim argumentem jest liczba operacji do wykonania na zestawie
    // semaforów (ilość elementów tablicy z argumentu drugiego)
    // operacje te wykonane będą w sposób niepodzielny ...
    // zobacz też: man 2 semop
  
  printf("%d: jestem za semaforem\n", pid);
  printf("%d: naciśnij enter aby zwolnic semafor\n", pid);
  while (getchar() != 10);
  
  (operacje[0]).sem_op = 1; // zwiększamy wartość semafora (zwalniamy)
  (operacje[0]).sem_flg = 0; // nie chcemy cofnięcia tej operacji
  semop (identyfikator_zestawu_semaforow, operacje, 1);
  
  printf("%d: semafor zwolniony\n", pid);
  
  /// usuwanie semafora
  (operacje[0]).sem_op = -2; // zwiększamy wartość semafora (zwalniamy)
  (operacje[0]).sem_flg = IPC_NOWAIT; // nie chcemy cofnięcia tej operacji
  if (semop (identyfikator_zestawu_semaforow, operacje, 1) != -1) {
    semctl (identyfikator_zestawu_semaforow, 0, IPC_RMID, 0);
    printf("%d: usuwam semafor\n", pid);
  } else {
    printf("%d: nie usuwam semafora\n", pid);
  }
  
  
/** PAMIEC WSPOLDZIELONA **/
  // tworzymy lub podłączamy się do fragmentu pamięci współdzielonej
  int deskryptor_pamieci_dzielonej = shmget(klucz, 100, 0640|IPC_CREAT | SHM_R | SHM_W);
  if (deskryptor_pamieci_dzielonej < 0) {
    printf("BŁĄD shmget: %i (%s)\n", errno, strerror(errno));
    return -1;
  }
  void * adres_pamieci_wspolnej = (void *) shmat(deskryptor_pamieci_dzielonej, NULL, 0);
  if ((int) adres_pamieci_wspolnej == -1) {
    printf("BŁĄD shmat: %i (%s)\n", errno, strerror(errno) );
    return -1;
  }
  
  // czytamy, zwiększamy o 1 i zapisujemy
  int *wartosc, old, new;
  wartosc = adres_pamieci_wspolnej;
  old = *wartosc;
  new = old + 1;
  *wartosc = new;
  printf("odczytałem %i, ustawiłem %i\n", old, new);
  
  // gdy wartosc > 5 usuwamy
  if (new > 5) {
    printf("Zlecam usunięcie wspólnego segmentu pamięci\n");
    // odłączamy od naszej przestrzeni adresowej
    shmdt(adres_pamieci_wspolnej);
    // zaznaczamy do usunięcia
    shmctl(deskryptor_pamieci_dzielonej, IPC_RMID, NULL);
  }
  
  
/** KOLEJKI KOMUNIKATOW **/
  
  
  // struktura opisująca komunikaty
  struct {
    long typ;
    char tresc[20];
  } komunikat;

  // uzyskujemy identyfikator kolejki komunikatów
  int identyfikator_kolejki_komunikatow = msgget(klucz, 0640|IPC_CREAT);
  if ( identyfikator_kolejki_komunikatow < 0) {
    printf("BŁĄD msgget: %i (%s)\n", errno, strerror(errno) );
    return -1;
  }
  
  
  // odbieramy komunikat ... jeżeli nie ma to nie czekamy
  if ( msgrcv(identyfikator_kolejki_komunikatow, &komunikat, sizeof(komunikat), 2, IPC_NOWAIT) < 0 ) {
    if (errno != ENOMSG) {
      printf("BŁĄD msgrcv: %i (%s)\n", errno, strerror(errno) );
      return -1;
    } else {
      printf("Brak komunikatów\n");
      
      // wysylamy komunikat
      komunikat.typ=2;
      strcpy(komunikat.tresc, "Hello");
      if ( msgsnd(identyfikator_kolejki_komunikatow, &komunikat, sizeof(komunikat), 0) < 0) {
        printf("BŁĄD msgsnd: %i (%s)\n", errno, strerror(errno) );
        return -1;
      }
      printf("Nadano komunikat: %s\n", komunikat.tresc);
    }
  } else {
    printf("Otrzymano komunikat: %s\n", komunikat.tresc);
    
    printf("Usuwam kolejkę komunikatów\n");
    // usuwamy kolejke komunikatów
    msgctl(identyfikator_kolejki_komunikatow, IPC_RMID, NULL);
  }
  
  return 0;
} 

XHTML generated by highlight (http://www.andre-simon.de/) from semafory_ipc.c



Copyright (c) 1999-2015, Robert Paciorek (http://www.opcode.eu.org/), BSD/MIT-type license


Redystrybucja wersji źródłowych i wynikowych, po lub bez dokonywania modyfikacji JEST DOZWOLONA, pod warunkiem zachowania niniejszej informacji o prawach autorskich. Autor NIE ponosi JAKIEJKOLWIEK odpowiedzialności za skutki użytkowania tego dokumentu/programu oraz za wykorzystanie zawartych tu informacji.

This text/program is free document/software. Redistribution and use in source and binary forms, with or without modification, ARE PERMITTED provided save this copyright notice. This document/program is distributed WITHOUT any warranty, use at YOUR own risk.

Valid XHTML 1.1 Dokument ten (URL: http://www.opcode.eu.org/programing/c_cpp/semafory_ipc.c) należy do serwisu OpCode. Autorem tej strony jest Robert Paciorek, wszelkie uwagi proszę kierować na adres e-mail serwisu: webmaster@opcode.eu.org.
Data ostatniej modyfikacji artykulu: '2014-01-07 19:27:41 (UTC)' (data ta może być zafałszowana niemerytorycznymi modyfikacjami artykułu).