-2

I'm trying to implement a real-world simulation involving synchronization, and when I have an event that has an 80% chance of occurring, I'm currently doing

  while((rand()%10)<8){
    up(sCar);
    printf("SOUTH: new car\n");
  }

However, the while loop is never triggering while ran, so I'm not sure if I'm using rand() properly. If I replace the rand() with 7, when it works properly. I currently set

  srand (time(NULL));

earlier in my program as well. Any help would be much appreciated.

EDIT: Here is the full running program. I have modified sys.c to create the system calls for up and down, which act as Semaphores.

#include <linux/unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <time.h>

struct cs1550_sem{
    int value;
    struct listnode *start;
    struct listnode *finish;
};

void up(struct cs1550_sem *sem) {
  syscall(__NR_cs1550_up, sem);
}

void down(struct cs1550_sem *sem) {
  syscall(__NR_cs1550_down, sem);
}

int main(void){

  srand (time(NULL));
  void * ptr = mmap(NULL, sizeof(struct cs1550_sem)*3, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, 0, 0);

  struct cs1550_sem *nCar = ((struct cs1550_sem *)ptr);
  struct cs1550_sem *sCar = ((struct cs1550_sem *)ptr) + 1;
  struct cs1550_sem *mutex = ((struct cs1550_sem *)ptr) + 2;
  struct cs1550_sem *flag = ((struct cs1550_sem *)ptr) + 3;

  void * northRoad = mmap(NULL, sizeof(int)*(10+1), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, 0, 0);
  void * southRoad = mmap(NULL, sizeof(int)*(10+1), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, 0, 0);

  nCar->value  = 0;
  nCar->start= NULL;
  nCar->finish    = NULL;

  sCar->value  = 0;
  sCar->start= NULL;
  sCar->finish  = NULL;

  flag->value  = 0;
  flag->start= NULL;
  flag->finish    = NULL;

  mutex->value  = 1;
  mutex->start= NULL;
  mutex->finish  = NULL;


  if(fork()==0){
    while(1){
      while((rand()%10)<8){
        up(nCar);
        printf("NORTH: new car\n");
      }
      printf("NORTH: no more cars, sleeping for 20 seconds\n");
      sleep(20);
    }
  }
  else if(fork()==0){
    while(1){
      while((rand()%10)<8){
        up(sCar);
        printf("SOUTH: new car\n");
      }
      printf("SOUTH: no more cars, sleeping for 20 seconds\n");
      sleep(20);
    }
  }
  else if(fork()==0){ 
    while(1){
      down(nCar);
      down(mutex); 
      printf("NORTH car allowed through\n");
      up(mutex);
    }
  }
  else{
    while(1){
      down(sCar);
      down(mutex);
      printf("SOUTH car allowed through\n");
      up(mutex);
    }
  }
  return 0;
}
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
bkrause404
  • 19
  • 8
  • What happens with `gcc -Wall` ? – Yunnosch Jun 25 '17 at 17:45
  • My physic powers tell me, that up(sCar) is executed and throws exception, that's why you dont see printf'ed text. Otherwise i dont see anything wrong with your code. – Radosław Cybulski Jun 25 '17 at 17:46
  • I get no exceptions when it is run, it just always loops to the "North car allowed through" and "south car allowed through" blocks. – bkrause404 Jun 25 '17 at 17:51
  • are you sure that your mutex/semaphore implementation works across processes (`fork()`)? Does ypur program works as expected without the up()/down() calls? – ensc Jun 25 '17 at 18:08
  • up and down works as semaphore (binary?), but which is which? Which one releases and which one tries to take ownership and locks if semaphpore is already taken? – Radosław Cybulski Jun 25 '17 at 18:08
  • 2
    The function `rand()` is not thread-safe. – Weather Vane Jun 25 '17 at 18:10
  • 2
    This is multiprocess, not multithreading (fork creates new process). – Radosław Cybulski Jun 25 '17 at 18:14
  • Did you separately unit test your `up` and `down` semaphore mods to `sys.c` to make sure they work as expected? – lurker Jun 25 '17 at 18:26
  • @Weather Van: What exactly do you mean by "not thread-safe"? – AnT stands with Russia Jun 25 '17 at 18:38
  • "event that has an 80% chance of occurring" - this is not exactly the same as a `while((rand()%10)<8)` cycle. If you have a single event, then why the cycle? If you have multiple events, then what is "80% chance"? – AnT stands with Russia Jun 25 '17 at 18:40
  • @AnT I meant because `rand` stores data internally and so is not re-entrant, but the OP has pointed out that threads are not being used. – Weather Vane Jun 25 '17 at 18:44
  • @Weather Vane: Just because some library function stores data locally does not mean that 1) it can't use thread-local storage, or 2) it can't implement synchronization internally. Some implementations provide different versions of standard library: single threaded or multi-threaded ones. This is exactly what makes them different. – AnT stands with Russia Jun 25 '17 at 18:46
  • @AnT I understood that `rand_r` is supposed to allow re-entrancy, because `rand` does not. – Weather Vane Jun 25 '17 at 18:49
  • 1
    Also, your initialization with `time` is by no means sufficien. All processes inherit the same sequence. To make the pseudo random series independent.in the different processes run `srand` after the `fork` and use something different than `time` for the seed, e.g the process id. – Jens Gustedt Jun 25 '17 at 19:16
  • @Weather Vane: You are confusing completely different kinds of "reentrancy". `rand_r` allows one to keep multiple independent random states, thus maintaining multiple independent random generators. `rand` is always a single generator with shared state. As long as a generator with shared state is what you need, `rand` is perfectly reentrant. Where you got the idea that it is not is not clear to me. – AnT stands with Russia Jun 25 '17 at 20:22
  • 1
    @AnT you don't understand how people understand what they understand? You are getting in quite a tangle. How else could there be a Stackoverflow? – Weather Vane Jun 25 '17 at 21:58

1 Answers1

0

I've always used this formula for getting a biased rand().I believe this gets a more even distribution than the modulo method.

#define RAND_PCT_THRESHOLD(x)  (int)(((long)(x) * RAND_MAX) / 100))

if (rand() <  RAND_PCT_THRESHOLD(80))
{
  // ...
)

What do you mean by

I have modified sys.c to create the system calls for up and down, which act as Semaphores.

I don't think that is a very good idea. Are you sure there is no easier and safer way to do atomic increments than modifying the runtime library? Your error may come from there, as the logic to the code you posted does look correct, and would probably run fine if you hadn't messed with the read-only-unless-there-is-a-bug-in-it runtime library.

When you allocate memory for your 'semaphores':

 void * ptr = mmap(NULL, sizeof(struct cs1550_sem)*3, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, 0, 0);

You allocate room for 3 semaphores, when you obviously need room for 4 of them.

  struct cs1550_sem *nCar = ((struct cs1550_sem *)ptr);
  struct cs1550_sem *sCar = ((struct cs1550_sem *)ptr) + 1;
  struct cs1550_sem *mutex = ((struct cs1550_sem *)ptr) + 2;
  struct cs1550_sem *flag = ((struct cs1550_sem *)ptr) + 3;
Michaël Roy
  • 6,338
  • 1
  • 15
  • 19