sem_close()?
  | (1) | _____ | 
A signal is said to be pending: | 
  | 
||
| (2) | _____ | 
A signal may have which of the following dispositions? | 
  | 
||
| (3) | _____ | 
A function is reentrant if: | 
  | 
||
| (4) | _____ | 
When a pipe/FIFO is empty: | 
  | 
||
| (5) | _____ | 
sem_post(): | 
  | 
||
| (6) | _____ | 
Which of the following are shared by all of the threads in a process? | 
  | 
| (1) | _____ | 
Interrupt handlers can be interrupted by signals | 
| (2) | _____ | 
Pipes/FIFOs guarantee writes (up to a certain size) are atomic | 
| (3) | _____ | 
Threads are often preferred to processes because they are easier to use with signals | 
| (4) | _____ | 
To avoid wasting resources, one must either call pthread_join() or pthread_detach() for every thread | 
| (5) | _____ | 
All thread-safe functions are reentrant | 
volatile int should = 0;
static void
sighandler(int sig)
{
  should = 1;
}
int
main(void)
{
  float rate, sales, tax;
  int   status;
  pid_t pid;
  rate   = 0.05;
  pid    = fork();
  signal(SIGUSR1, sighandler);
  switch(pid)
    {
    case -1:
      exit(1);
    case 0:
      if (should_tax())
        {
          // Add your code here
        }
      break;
    default:
      sales = total_sales();
      wait(&status);
      if (should) tax = sales * rate;
      else        tax = 0.0;
      printf("Tax: %5.2f\n", tax);
      break;
    }
}
wait()?
    waitpid() in this case?
    total_sales() is 100.00?
    should_tax() returns "true", this program is
    supposed to print Tax: 5.00. What will be printed if
    you replace the line // Add your code here with 
    should = 1? Why?
    //Add your code here with one or
    more statements that will make the program work correctly.
    Task 1 before
  it prints Task 2.
static void
handle_continue(int sig)
{
  // Nothing to do
}
int
main(void)
{
  // Setup the signal handler
  signal(SIGCONT, handle_continue);
  pid_t  pid = fork();
  switch(pid)
    {
    case -1:
      exit(1);
    case 0:
      printf("Task 1\n");
      kill(getppid(), SIGCONT);
      exit(0);
    default:
      pause();
      printf("Task 2\n");
      exit(0);
    }
}
pause()?
    pause() return?
    
int
main(void)
{
  char  msg[20];
  int   fd_pipe[2];
  int   n, status;
  pid_t pid;
  pipe(fd_pipe);
  
  pid    = fork();
  switch(pid)
    {
    case -1:
      exit(1);
    case 0:
      close(fd_pipe[1]);
      read(fd_pipe[0], msg, 20);
      close(fd_pipe[0]);
      write(STDOUT_FILENO, msg, 20);
      exit(0);
    default:
      close(fd_pipe[0]);
      write(fd_pipe[1], "Because I said so!\n\0", 20); 
      close(fd_pipe[1]);
      wait(&status);
      exit(0);
    }
}
close(fd_pipe[1]) before the call to read()?
    close(fd_pipe[0]) after the call to read()?
    fd_pipe contain two elements? In
    other words, what are the two elements used for?
    close(fd_pipe[1]) before the parent process
    executes write(fd_pipe[1], "Because I said so!\n\0", 20), 
    will the call to write() fail? Why or why not?
    
int
main(void)
{
  pid_t  pid = fork();
  switch(pid)
    {
    case -1:
      exit(1);
    case 0:
      write(STDOUT_FILENO, "A1 ", 3);
      write(STDOUT_FILENO, "A2 ", 3);
      exit(0);
    default:
      write(STDOUT_FILENO, "B1 ", 3);
      write(STDOUT_FILENO, "B2 ", 3);
      exit(0);
    }
}
static void
*count(void *arg)
{
  char *s;
  void *result;
  s = (char *)arg;
  result = (void *)(strlen(s));
  return result;
}
int
main(void)
{
  char       *s;
  int        i;
  long       len;
  pthread_t  helper[5];
  void       *result;
  s = "James Madison University";
  len = strlen(s);
  
  for (i=0; i<5; i++)
    {
      pthread_create(&helper[i], NULL, count, s+(i*2));
    }
  for (i=0; i<5; i++)
    {
      pthread_join(helper[i], &result);
      len += (long)result;
    }
  printf("Characters printed: %ld\n", len);
  exit(0);
}
pthread_detach() rather than
    pthread_join()?
    
int count;
static void
*thread_entry(void *arg)
{
  count += 5;
  return NULL;
}
int
main(void)
{
  pthread_t thread1;
  count = 10;
  printf("Before: %d\n", count);
  pthread_create(&thread1, NULL, code_for_thread1, NULL);
  pthread_join(thread1, NULL);
  printf("After: %d\n", count);
  exit(0);
}
static volatile int global_counter = 0;
static void*
counter(void *arg)
{
  int   i, limit, local_counter;
  limit = *((int *) arg);
  for (i=0; i<limit; i++)
    {
      local_counter = global_counter;
      ++local_counter;
      global_counter = local_counter;
    }
  
  return NULL;
}
int
main(int argc, char *argv[])
{
  int        limit;
  pthread_t  thread_a, thread_b;
  
  if (argc <= 1) limit = 100;
  else           limit = atoi(argv[1]);
  // Start two threads counting
  pthread_create(&thread_a, NULL, counter, &limit);
  pthread_create(&thread_b, NULL, counter, &limit);
  // Wait for both threads to terminate
  pthread_join(thread_a, NULL);
  pthread_join(thread_b, NULL);
  // Display the result
  printf("Expected: %d\n", limit*2);
  printf("Actual:   %d\n", global_counter);
  exit(0);
}
  but contains a defect known as a read-modify-write condition (a particular
  kind of race condition). Use one or more pthread_mutex_t
  variables to eliminate this defect.
  
static int should = -1;         // Shared variable
static void
*thread_entry(void *arg)
{
  if (should_tax()) should = 1;
  else              should = 0;
  
  record_status(); // This takes a long time
  return NULL;
}
int
main(void)
{
  float       rate, sales, tax;
  pthread_t   helper;
  void        *result;
  pthread_create(&helper, NULL, thread_entry, NULL);
  
  rate = 0.05;
  sales = total_sales();
  
  if (should) tax = sales * rate;
  else        tax = 0.0;
  
  printf("Tax: %5.2f\n", tax);
  pthread_join(helper, &result);
  exit(0);
}
  Specifically, the main thread may use the shared variable 
  named should before the helper thread assigns a value to it.
  
pthread_mutex_t variable and polling.
    pthread_cond_t
    variable.
    Copyright 2017