User Tools

Site Tools


Sidebar

os_cp:semaphores:solutions

Exercise 1

#include <fcntl.h>
#include <semaphore.h>
#include <stdio.h>
 
int main() {
  sem_t *mySemaphore = sem_open("/mySemaphore", O_CREAT | O_EXCL, 0666, 0);
  if (mySemaphore == SEM_FAILED) {
    perror("Creating the semaphore failed");
    return 1;
  }
  sem_wait(mySemaphore);
  return 0;
}
#include <fcntl.h>
#include <semaphore.h>
#include <stdio.h>
 
int main() {
  sem_t *mySemaphore = sem_open("/mySemaphore", 0, 0666, 0);
  if (mySemaphore == SEM_FAILED) {
    perror("Opening the semaphore failed");
    return 1;
  }
  sem_post(mySemaphore);
  return 0;
}

Exercise 2

#include <fcntl.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
 
#define MAX_ELEMENTS 4
typedef char item_t[256];
 
struct ring_buffer {
  item_t data[MAX_ELEMENTS];
  size_t first;
  size_t last;
};
 
struct ring_buffer *buffer;
 
sem_t *storedItemsCount;
sem_t *emptyItemsCount;
sem_t *canModify;
 
void put(struct ring_buffer *buffer, const item_t *item) {
  sem_wait(emptyItemsCount);
  sem_wait(canModify);
  memcpy(&buffer->data[buffer->last], item, sizeof(*item));
  buffer->last = (buffer->last + 1) % MAX_ELEMENTS;
  sem_post(canModify);
  sem_post(storedItemsCount);
}
 
void get(struct ring_buffer *buffer, item_t *item) {
  sem_wait(storedItemsCount);
  sem_wait(canModify);
  memcpy(item, &buffer->data[buffer->first], sizeof(*item));
  buffer->first = (buffer->first + 1) % MAX_ELEMENTS;
  sem_post(canModify);
  sem_post(emptyItemsCount);
}
 
int main() {
  int fd = shm_open("/myRingBuffer", O_RDWR | O_CREAT, 0666);
  if (fd == -1) { perror("shm_open"); exit(1); }
  ftruncate(fd, sizeof(struct ring_buffer));
  buffer = mmap(NULL, sizeof(struct ring_buffer), PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
 
  storedItemsCount = sem_open("myRingBuffer.storedItems", O_RDWR | O_CREAT, 0666, 0);
  emptyItemsCount  = sem_open("myRingBuffer.emptyItems",  O_RDWR | O_CREAT, 0666, 4);
  canModify        = sem_open("myRingBuffer.canModify",   O_RDWR | O_CREAT, 0666, 1);
 
  printf("g             gets data from buffer\n"
         "ptext...      puts 'text...' to buffer\n");
  while (1) {
    printf("> ");
    fflush(stdout);
    char cmd[2], c;
    item_t item = {0};
    scanf("%1[^\n]%255[^\n]", cmd, item);
    do { // this reads all remaining characters in this line including '\n'
      c = getchar();
      if (c == -1)
        return 0;
    } while (c != '\n');
    switch (cmd[0]) {
    case 'p':
      put(buffer, &item);
      break;
    case 'g':
      get(buffer, &item);
      printf("%s\n", item);
      break;
    }
  }
  return 0;
}

Exercise 3

Line:

 if (createSucceeded) sleep(10);

added anywhere after line 13 and before line 22 delays the first process from initializing the semaphore for 10 seconds. If another process attempts to wait on uninitialized semaphore, it is likely to get stuck forever.

Exercise 4

Lines between sem_wait and sem_post are the critical region.

Exercise 5

When the program is run concurrently with arguments 0 1 and 1 0, it will deadlock if both processes manage to acquire the first semaphore (respectively 0 for the first process, and 1 for the second) and then try to acquire the second one (respectively 1 and 0).

Exercise 6

One of the simpler solutions is to wait on semaphores in a predefined order, that is instead of:

    sem_wait(&data->item[argOne].sem);
    sem_wait(&data->item[argTwo].sem);

one may just:

    sem_wait(&data->item[argOne<argTwo?argOne:argTwo].sem);
    sem_wait(&data->item[argOne<argTwo?argTwo:argOne].sem);

os_cp/semaphores/solutions.txt · Last modified: 2023/09/15 15:18 by jkonczak