| Thread-Specific Data in Pthreads | 
| 
                      Prof. David Bernstein | 
| Computer Science Department | 
| bernstdh@jmu.edu | 
         
      
int pthread_key_create(pthread_key_t *key, void (*destructor)(void *)
               | key | A key that can be used to obtain thread-specific data | 
| destructor | The function to call to free the thread-specific memory (or NULL if no destructor is needed) | 
| Return | 0 on success; a positive error number on error | 
Note: destructor() will be invoked automatically by the
system when the thread terminates (and passed the address of the
thread-specific memory for this key).
int pthread_setspecific(pthread_key_t key, const void *value)
               | key | The key used to identify the thread-specific data | 
| value | The value to save (which is normally a block of memory that has been previously allocated by the caller) | 
| Return | 0 on success; a positive error number on error | 
#include "grader.h"
#include <string.h>
char
*letter_grade(float number_grade)
{
  char letter[2];
  if      (number_grade >= 90.0) strncpy(letter, "A", 1);
  else if (number_grade >= 80.0) strncpy(letter, "B", 1);
  else if (number_grade >= 70.0) strncpy(letter, "C", 1);
  else if (number_grade >= 60.0) strncpy(letter, "D", 1);
  else                           strncpy(letter, "F", 1);
  letter[1] = '\0';
  
  return letter;
}
        
         A Driver with Multiple Threads
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "grader.h"
static void
*thread_entry(void *arg)
{
  float number_grade = *(float *)arg;
  //void  *result = (void *)letter_grade(number_grade);
  //return result;
  printf("Thread: %s\n", letter_grade(number_grade));
  return NULL;
}
int
main(void)
{
  char        *letter_main;
  float       number_helper;
  pthread_t   exam_helper;
  // Calculate one letter grade in the main thread
  letter_main = letter_grade(85.5);
  // Calculate (and print) another letter grade in the helper thread
  number_helper = 48.0;
  pthread_create(&exam_helper, NULL, thread_entry, &number_helper);
  // Terminate the helper thread
  pthread_join(exam_helper, NULL);
  // Now that the helper thread has terminated, print the
  // grade that was calculated in the main thread
  printf("Main: %s\n", letter_main);
  return 0;
}
        
         #include "grader.h"
#include <string.h>
char
*letter_grade(float number_grade)
{
  static char letter[2];
  if      (number_grade >= 90.0) strncpy(letter, "A", 1);
  else if (number_grade >= 80.0) strncpy(letter, "B", 1);
  else if (number_grade >= 70.0) strncpy(letter, "C", 1);
  else if (number_grade >= 60.0) strncpy(letter, "D", 1);
  else                           strncpy(letter, "F", 1);
  letter[1] = '\0';
  
  return letter;
}
        
         #include "grader.h"
#include <string.h>
static char letter[2];
char
*letter_grade(float number_grade)
{
  if      (number_grade >= 90.0) strncpy(letter, "A", 1);
  else if (number_grade >= 80.0) strncpy(letter, "B", 1);
  else if (number_grade >= 70.0) strncpy(letter, "C", 1);
  else if (number_grade >= 60.0) strncpy(letter, "D", 1);
  else                           strncpy(letter, "F", 1);
  letter[1] = '\0';
  
  return letter;
}
        
         #include "grader.h"
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static pthread_key_t   grader_key;
static pthread_once_t  grader_once = PTHREAD_ONCE_INIT;
static
void free_memory(void *buffer)
{
  free(buffer);
}
static
void create_key(void)
{
  pthread_key_create(&grader_key, free_memory);
}
char
*letter_grade(float number_grade)
{
  char *letter;
  
  // The first caller must create the key for the thread-specific data
  pthread_once(&grader_once, create_key);
  
  // Get the memory for the key
  letter = pthread_getspecific(grader_key);
  
  // If this is the first call from this thread then the memory
  // will be NULL and, hence, must be allocated (and saved)
  if (letter == NULL)
    {
      letter = malloc(2);
      pthread_setspecific(grader_key, letter);
    }
  if      (number_grade >= 90.0) strncpy(letter, "A", 1);
  else if (number_grade >= 80.0) strncpy(letter, "B", 1);
  else if (number_grade >= 70.0) strncpy(letter, "C", 1);
  else if (number_grade >= 60.0) strncpy(letter, "D", 1);
  else                           strncpy(letter, "F", 1);
  letter[1] = '\0';
  return letter;
}