Translate

Chủ Nhật, 4 tháng 12, 2016

Thread in Linux

created by Frank

What is a thread?

Like processes, threads are a mechanism that permits an application to perform multiple tasks concurrently. 

threads in process

thread stack in virtual memory address

thread life

Creating a thread

using the following functions to create a thread:

  1. #include <pthread.h><pthread .h="">  
  2. /*create a thread*/  
  3. int pthread_create(pthread_t *threadconst pthread_attr_t *attr, </pthread>  
  4. void *(*start_routine) (void *), void *arg);  
  5.   
  6. /*wait a thread finishing and get return value*/  
  7. int pthread_join(pthread_t *threadvoid **retval);  
  8.   
  9. /*thread returns value*/  
  10. int pthread_exit(void *retval);  
?
example

  1. #include <stdio.h>  
  2. #include <pthread.h>  
  3. static void *threadFunc(void *arg)  
  4. {  
  5.     char *s = (char *) arg;  
  6.     printf("%s", s);  
  7.    
  8.     pthread_exit("thread finishes");  
  9. }  
  10.    
  11. int main(int argc, char *argv[])  
  12. {  
  13.     pthread_t t1;  
  14.     void *res;  
  15.     int s;  
  16.    
  17.     s = pthread_create(&t1, NULL, threadFunc, "Hello world\n");  
  18.     if (s != 0)  
  19.         printf("pthread_create");  
  20.    
  21.     printf("Message from main()\n");  
  22.     s = pthread_join(t1, &res);  
  23.     if (s != 0)  
  24.         printf("pthread_join");  
  25.    
  26.     printf("Thread returned %s\n", (char *) res);  
  27.    
  28.     exit(EXIT_SUCCESS);  
  29. }  
?
?
note: compile and link with -lpthread

some data type defined in pthread.h header file
data types in pthread.h
fork() in a thread

  • To the Linux kernel, there is no concept of a thread
  • Linux implements all threads as standard processes
  • Child process from the parent is that the child has only one thread, the fork() call clones just the thread which executed it.

Thread attributes

with attributes, we have many options to control threads
the thread attributes object

?
1
pthread_attr_t attr;
defination of pthread_attr_t
?
1
2
3
4
5
6
7
8
9
10
11
typedef struct {
    int __detachstate;
    int __schedpolicy;
    struct sched_param __schedparam;
    int __inheritsched;
    int __scope;
    size_t __guardsize;
    int __stackaddr_set;
    void *__stackaddr;
    unsigned long int __stacksize;
} pthread_attr_t;

firstly, we must initialize the attr
?
1
pthread_attr_init(pthread_attr_t *attr);

and, we must destroy the attr after using
?
1
pthread_attr_destroy(pthread_attr_t *attr);

Detachedstate

sometimes we don't want to a thread join to main thread, so we use detachedstate attribute.
There are 2 methods to detach a thread. After detaching, the thread can not join to main thread
Method 1; use pthread_detach(pthread_t thread);  

  • call in main thread: pthread_detach(thread);
  • call in the detach thread: pthread_detach(thread_self());

if we use this system call, after that calling thread_join will return error
example
?
  1. #include <stdio.h>  
  2. #include <unistd.h>  
  3. #include <stdlib.h>  
  4. #include <pthread.h>  
  5.   
  6. void *thread_function(void *arg);  
  7. char message[] = "Hello World";  
  8. int thread_finished = 0;  
  9. void *thread_result;  
  10.    
  11. int main() {  
  12.  int res, s;  
  13.  pthread_t a_thread;  
  14.  pthread_attr_t thread_attr;  
  15.    
  16.  res = pthread_create(&a_thread, &thread_attr, thread_function, (void *)message);  
  17.  pthread_detach(a_thread);  
  18.    
  19.  s = pthread_join(a_thread,&thread_result);  
  20.  if(s != 0)  
  21.   printf("error to join\n");  
  22.     
  23.  (void)pthread_attr_destroy(&thread_attr);  
  24.  while(!thread_finished) {  
  25.   printf("Waiting for thread to say it's finished...\n");  
  26.   sleep(1);  
  27.  }  
  28.  printf("Other thread finished, bye!\n");  
  29.  exit(EXIT_SUCCESS);  
  30. }  
  31.    
  32. void *thread_function(void *arg)   
  33. {  
  34.  //pthread_detach(pthread_self());  
  35.  printf("thread_function is running. Argument was %s\n", (char *)arg);  
  36.  sleep(4);  
  37.  printf("Second thread setting finished flag, and exiting now\n");  
  38.  thread_finished = 1;  
  39.  pthread_exit(NULL);  
  40. }  

Method 2:
there are 2 flags: PTHREAD_CREATE_JOINABLE and PTHREAD_CREATE_DETACHED of
use the call to set detach state for attr object:
?
1
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
use this call to get detach state:
?
1
int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate); 
example: 
?
  1. #include <stdio.h>  
  2. #include <unistd.h>  
  3. #include <stdlib.h>  
  4. #include <pthread.h>  
  5.   
  6. void *thread_function(void *arg);  
  7. char message[] = "Hello World";  
  8. int thread_finished = 0;  
  9. void *thread_result;  
  10.    
  11. int main() {  
  12.  int res;  
  13.  pthread_t a_thread;  
  14.  pthread_attr_t thread_attr;  
  15.    
  16.  res = pthread_attr_init(&thread_attr);  
  17.  res = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);  
  18.  res = pthread_create(&a_thread, &thread_attr, thread_function, (void *)message);  
  19.    
  20.  pthread_join(a_thread,&thread_result);  
  21.  (void)pthread_attr_destroy(&thread_attr);  
  22.  while(!thread_finished) {  
  23.   printf("Waiting for thread to say it's finished...\n");  
  24.   sleep(1);  
  25.  }  
  26.  printf("Other thread finished, bye!\n");  
  27.  exit(EXIT_SUCCESS);  
  28. }  
  29.    
  30. void *thread_function(void *arg)   
  31. {  
  32.  printf("thread_function is running. Argument was %s\n", (char *)arg);  
  33.  sleep(4);  
  34.  printf("Second thread setting finished flag, and exiting now\n");  
  35.  thread_finished = 1;  
  36.  pthread_exit(NULL);  
  37. }  

Schedpolicy

This controls how threads are scheduled.
Use 2 functions:
?
1
2
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy);

3 flags:

  • SCHED_OTHER: default
  • SCHED_RR: (only running process with super permission, real time scheduling), uses the round-robin scheduling scheme
  • SCHED_FIFO: (only running process with super permission, real time scheduling), uses the firsts in - first out scheduling scheme

Schedparam

In schedpolicy, if we choose policy is SCHED_OTHER, this is a parter to schedpolicy and allows control over the scheduling of threads
?
  1. int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);  
  2. int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);  
  3.   
  4. where:  
  5.   
  6. const struct sched_param{  
  7.   int sched_priority;  
  8. }  

Inherisched

use 2 functions:

?
1
2
int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit);
int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit);
    2 flags of inherit:
    • PTHREAD_EXPLICIT_SCHED (default): scheduling is explicitly set by the attributes
    • PTHREAD_INHERIT_SCHED: a new thread will instead use the parametters that its creator thread was using

    example
    ?

    1. /* pthreads_sched_test.c */  
    2.    
    3. #include <pthread.h><pthread .h="">  
    4. #include <stdio.h><stdio .h="">  
    5. #include <stdlib.h><stdlib .h="">  
    6. #include <errno.h><unistd .h="">  
    7. #include <unistd.h><errno .h="">  
    8.    
    9. #define handle_error_en(en, msg) \  
    10.         do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)  
    11.    
    12. static void  
    13. usage(char *prog_name, char *msg)  
    14. {  
    15.     if (msg != NULL)  
    16.         fputs(msg, stderr);  
    17.    
    18.     fprintf(stderr, "Usage: %s [options]\n", prog_name);  
    19.     fprintf(stderr, "Options are:\n");  
    20.     #define fpe(msg) fprintf(stderr, "\t%s", msg);          /* Shorter */  
    21.     fpe("-a<policy><prio> Set scheduling policy and priority in\n");  
    22.     fpe("                 thread attributes object\n");  
    23.     fpe("                 <policy> can be\n");  
    24.     fpe("                     f  SCHED_FIFO\n");  
    25.     fpe("                     r  SCHED_RR\n");  
    26.     fpe("                     o  SCHED_OTHER\n");  
    27.     fpe("-A               Use default thread attributes object\n");  
    28.     fpe("-i {e|i}         Set inherit scheduler attribute to\n");  
    29.     fpe("                 'explicit' or 'inherit'\n");  
    30.     fpe("-m<policy><prio> Set scheduling policy and priority on\n");  
    31.     fpe("                 main thread before pthread_create() call\n\n");  
    32.     exit(EXIT_FAILURE);  
    33. }  
    34.    
    35. static int  
    36. get_policy(char p, int *policy)  
    37. {  
    38.     switch (p) {  
    39.     case 'f': *policy = SCHED_FIFO;     return 1;  
    40.     case 'r': *policy = SCHED_RR;       return 1;  
    41.     case 'o': *policy = SCHED_OTHER;    return 1;  
    42.     default:  return 0;  
    43.     }  
    44. }  
    45.    
    46. static void  
    47. display_sched_attr(int policy, struct sched_param *param)  
    48. {  
    49.     printf("    policy=%s, priority=%d\n",  
    50.             (policy == SCHED_FIFO)  ? "SCHED_FIFO" :  
    51.             (policy == SCHED_RR)    ? "SCHED_RR" :  
    52.             (policy == SCHED_OTHER) ? "SCHED_OTHER" :  
    53.             "???",  
    54.             param->sched_priority);  
    55. }  
    56.    
    57. static void  
    58. display_thread_sched_attr(char *msg)  
    59. {  
    60.     int policy, s;  
    61.     struct sched_param param;  
    62.    
    63.     s = pthread_getschedparam(pthread_self(), &policy, ¶m);  
    64.     if (s != 0)  
    65.         handle_error_en(s, "pthread_getschedparam");  
    66.    
    67.     printf("%s\n", msg);  
    68.     display_sched_attr(policy, ¶m);  
    69. }  
    70.    
    71. static void *  
    72. thread_start(void *arg)  
    73. {  
    74.     display_thread_sched_attr("Scheduler attributes of new thread");  
    75.    
    76.     return NULL;  
    77. }  
    78.    
    79. int  
    80. main(int argc, char *argv[])  
    81. {  
    82.     int s, opt, inheritsched, use_null_attrib, policy;  
    83.     pthread_t thread;  
    84.     pthread_attr_t attr;  
    85.     pthread_attr_t *attrp;  
    86.     char *attr_sched_str, *main_sched_str, *inheritsched_str;  
    87.     struct sched_param param;  
    88.    
    89.     /* Process command-line options */  
    90.    
    91.     use_null_attrib = 0;  
    92.     attr_sched_str = NULL;  
    93.     main_sched_str = NULL;  
    94.     inheritsched_str = NULL;  
    95.    
    96.     while ((opt = getopt(argc, argv, "a:Ai:m:")) != -1) {  
    97.         switch (opt) {  
    98.         case 'a': attr_sched_str = optarg;      break;  
    99.         case 'A': use_null_attrib = 1;          break;  
    100.         case 'i': inheritsched_str = optarg;    break;  
    101.         case 'm': main_sched_str = optarg;      break;  
    102.         default:  usage(argv[0], "Unrecognized option\n");  
    103.         }  
    104.     }  
    105.    
    106.     printf("%s %s %s\n", main_sched_str, attr_sched_str, inheritsched_str);  
    107.    
    108.     if (use_null_attrib && (inheritsched_str != NULL || attr_sched_str != NULL))  
    109.         usage(argv[0], "Can't specify -A with -i or -a\n");  
    110.    
    111.     /* Optionally set scheduling attributes of main thread, 
    112.        and display the attributes */  
    113.    
    114.     if (main_sched_str != NULL) {  
    115.         if (!get_policy(main_sched_str[0], &policy))  
    116.             usage(argv[0], "Bad policy for main thread (-m)\n");  
    117.         param.sched_priority = strtol(&main_sched_str[1], NULL, 0);  
    118.    
    119.         s = pthread_setschedparam(pthread_self(), policy, ¶m);  
    120.         if (s != 0)  
    121.             handle_error_en(s, "pthread_setschedparam");  
    122.     }  
    123.    
    124.     display_thread_sched_attr("Scheduler settings of main thread");  
    125.     printf("\n");  
    126.    
    127.     /* Initialize thread attributes object according to options */  
    128.    
    129.     attrp = NULL;  
    130.    
    131.     if (!use_null_attrib) {  
    132.         s = pthread_attr_init(&attr);  
    133.         if (s != 0)  
    134.             handle_error_en(s, "pthread_attr_init");  
    135.         attrp = &attr;  
    136.     }  
    137.    
    138.     if (inheritsched_str != NULL) {  
    139.         if (inheritsched_str[0] == 'e')  
    140.             inheritsched = PTHREAD_EXPLICIT_SCHED;  
    141.         else if (inheritsched_str[0] == 'i')  
    142.             inheritsched = PTHREAD_INHERIT_SCHED;  
    143.         else  
    144.             usage(argv[0], "Value for -i must be 'e' or 'i'\n");  
    145.    
    146.         s = pthread_attr_setinheritsched(&attr, inheritsched);  
    147.         if (s != 0)  
    148.             handle_error_en(s, "pthread_attr_setinheritsched");  
    149.     }  
    150.    
    151.     if (attr_sched_str != NULL) {  
    152.         if (!get_policy(attr_sched_str[0], &policy))  
    153.             usage(argv[0],  
    154.                     "Bad policy for 'attr' (-a)\n");  
    155.         param.sched_priority = strtol(&attr_sched_str[1], NULL, 0);  
    156.    
    157.         s = pthread_attr_setschedpolicy(&attr, policy);  
    158.         if (s != 0)  
    159.             handle_error_en(s, "pthread_attr_setschedpolicy");  
    160.         s = pthread_attr_setschedparam(&attr, ¶m);  
    161.         if (s != 0)  
    162.             handle_error_en(s, "pthread_attr_setschedparam");  
    163.     }  
    164.    
    165.     /* If we initialized a thread attributes object, display 
    166.        the scheduling attributes that were set in the object */  
    167.    
    168.     if (attrp != NULL) {  
    169.         s = pthread_attr_getschedparam(&attr, ¶m);  
    170.         if (s != 0)  
    171.             handle_error_en(s, "pthread_attr_getschedparam");  
    172.         s = pthread_attr_getschedpolicy(&attr, &policy);  
    173.         if (s != 0)  
    174.             handle_error_en(s, "pthread_attr_getschedpolicy");  
    175.    
    176.         printf("Scheduler settings in 'attr'\n");  
    177.         display_sched_attr(policy, ¶m);  
    178.    
    179.         s = pthread_attr_getinheritsched(&attr, &inheritsched);  
    180.         printf("    inheritsched is %s\n",  
    181.                 (inheritsched == PTHREAD_INHERIT_SCHED)  ? "INHERIT" :  
    182.                 (inheritsched == PTHREAD_EXPLICIT_SCHED) ? "EXPLICIT" :  
    183.                 "???");  
    184.         printf("\n");  
    185.     }  
    186.    
    187.     /* Create a thread that will display its scheduling attributes */  
    188.    
    189.     s = pthread_create(&thread, attrp, &thread_start, NULL);  
    190.    
    191.     s = pthread_join(thread, NULL);  
    192.     if (s != 0)  
    193.         handle_error_en(s, "pthread_join");  
    194.    
    195.     exit(EXIT_SUCCESS);  
    196. }  
    197. </prio></policy></policy></prio></policy></errno></unistd></stdlib></stdio></pthread>  

    Scope

    This attribute controls how scheduling of a thread is calculated. Since Linux only currently supports the value PTHREAD_SCOPE_SYSTEM, we will not look at this further here

    Stacksize

    Linux implements threads with a large amount of stack by default, so the feature is generally redundant on Linux and consequently not implemented.
    To set the stacksize of thread, use:
    ?
    1
    int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
    To get the stacksize of thread, use
    ?
    1
    2
    $ulimit -s
    8192   # The stack size limit is 8 MB
    or
    ?
    1
    int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *stacksize);


    Thread cancellation 

    the function to request a thread to terminate
    ?

    1. int pthread_cancel(pthread_t thread);  
    2.     
    3. //set cancel state  
    4. int pthread_setcancelstate(int state, int *oldstate);  
    5.    
    6. //states:  
    7. PTHREAD_CANCEL_ENABLE: default  
    8.   
    9. PTHREAD_CANCEL_DISABLE: cancellation is disable  
    10.   
    11. //set cancel type  
    12. int pthread_setcanceltype(int type, int *oldtype);  
    13.   
    14. //types:  
    15. PTHREAD_CANCEL_ASYNCHRONOUS: cancel immediatetly  
    16. PTHREAD_CANCEL_DEFERRER: wait until the cancellation point excution.  
    Cancellation points in linux
    cancellation points
    Another method to create a cancellation point: void pthread_testcancel(void);
    Cleanup handlers:
    ?
    1
    2
    3
    4
    #include <pthread.h><pthread .h="">
    void pthread_cleanup_push(void (*routine)(void*), void *arg);
    void pthread_cleanup_pop(int execute);
    </pthread>
    example
    ?
    1. #include <stdio.h>  
    2. #include <pthread.h>  
    3.   
    4. void *threadFunc(void *arg)  
    5. {  
    6.  int j; int i=0;  
    7.  //pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);  
    8.  //pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);  
    9.  //pthread_setcanceltype(PTHREAD_CANCEL_DEFERRER, NULL);  
    10.  printf("new thread start\n");  //may be a cancellation point  
    11.  for (j = 1; ; ++j)  
    12.  {  
    13.   i++;            
    14.   //pthread_testcancel();  
    15.  }  
    16.  printf("Loop %d\n", j); //may be a cancellation point   
    17.  sleep(1);   //a cancellation point  
    18.  return NULL;  
    19. }  
    20.    
    21. int main(int argc, char *argv[])  
    22. {  
    23.  pthread_t thr;  
    24.  int s;  
    25.  void *res;  
    26.    
    27.  pthread_create(&thr, NULL, &threadFunc, NULL);  
    28.  sleep(3);  
    29.    
    30.  pthread_cancel(thr);  
    31.    
    32.  pthread_join(thr, &res);  
    33.    
    34.  if(res == PTHREAD_CANCELED)  
    35.   printf("thread was cancel\n");  
    36.  else printf("thread was not canceled (should not happen!)\n");  
    37.    
    38.  return 0;  
    39. }  

    Thread synchronization

    Mutex

    Statically allocated mutexes
    ?
    1
    pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
    Dynamically allocated mutexes
    ?
    1
    2
    3
    4
    pthread_mutex_t mtx;
    pthread_mutexattr_t attr;
     
    int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
    Locking and unlocking a mutex
    ?

    1. /*lock mutex, blocking*/  
    2. int pthread_mutex_lock(pthread_mutex_t *mtx);  
    3.   
    4. /*unlock mutex*/  
    5. int pthread_mutex_unlock(pthread_mutex_t *mtx);  
    6.   
    7. /*lock mutex, non-blocking*/  
    8. int pthread_mutex_trylock(pthread_mutex_t *mtx);  
    9.   
    10. /*lock mutex, timeout*/  
    11. int pthread_mutex_timelock(pthread_mutex_t *mtx);  

     
    Example:
    ?
    1. #include <stdio.h>
    2. #include <pthread.h> 
    3.    
    4. pthread_mutex_t mutex;  
    5. int count;  
    6.    
    7.    
    8. void* func(void *arg) {  
    9.   pthread_mutex_lock(&mutex);  
    10.   printf("This is thread %d\n",*(int*)arg);  
    11.   printf("count = %d\n", count++);  
    12.   sleep(1);  
    13.   pthread_mutex_unlock(&mutex);  
    14. }  
    15.    
    16. int main(int argc, char **argv)  
    17. {  
    18.  int i;  
    19.  pthread_t tid[5];  
    20.  count=0;  
    21.  pthread_mutex_init(&mutex,NULL);  
    22.    
    23.  for(i=0; i < 5; i++)  
    24.  {  
    25.   pthread_create(&tid[i],NULL,func, (void*)&tid[i]);  
    26.      
    27.  }  
    28.  for(i=0; i < 5; i++)  
    29.  {  
    30.   pthread_join(&tid[i],NULL);  
    31.  }  
    32.  return 0;  
    33. }  


    Performance of mutexes

    Programs without mutexes is faster programs using mutexes, but in the typical case, a thread would spend much more time doing other work, and perform relatively fewer mutex lock and unlock operations, so that the performance impact of using a mutex is not significant in most applications.

    Mutex deadlock

    mutex deadlock

    Condition variable

    A condition variable allows one thread to inform other threads about changes in the state of a shared variable (or other shared resource) and allows the other threads to wait (block) for such notification

    1. /*statically*/  
    2. pthread_cond_t cond= PTHREAD_COND_INITIALIZER;  
    3.    
    4. /*dynamically*/  
    5. pthread_cond_t cond;  
    6. pthread_conattr_t attr;  
    7.    
    8. int pthread_cond_init(phtread_cond_t *cond, const pthread_conattr_t *attr);  

    Example: 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    #include <time.h="">
    #include <pthread.h>
    #include <stdio.h>
     
    static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
    static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
     
    static int avail = 0;
     
    static void *
    threadFunc(void *arg)
    {
        int cnt = atoi((char *) arg);
        int s, j;
     
        for (j = 0; j < cnt; j++) {
            sleep(1);
     
            /* Code to produce a unit omitted */
     
            s = pthread_mutex_lock(&mtx);
            if (s != 0)
                printf("pthread_mutex_lock");
     
            avail++;        /* Let consumer know another unit is available */
     
            s = pthread_mutex_unlock(&mtx);
            if (s != 0)
                printf("pthread_mutex_unlock");
     
            s = pthread_cond_signal(&cond);         /* Wake sleeping consumer */
            if (s != 0)
                printf("ptread_cond_signal");
        }
     
        return NULL;
    }
     
    int
    main(int argc, char *argv[])
    {
        pthread_t tid;
        int s, j;
        int totRequired;            /* Total number of units that all threads
                                       will produce */
        int numConsumed;            /* Total units so far consumed */
        int done;
        time_t t;
     
        t = time(NULL);
        /* Create all threads */
     
        totRequired = 0;
        for (j = 1; j < argc; j++) {
            totRequired += atoi(argv[j]);
     
            s = pthread_create(&tid, NULL, threadFunc, argv[j]);
            if (s != 0)
                printf("pthread_create");
        }
     
        /* Loop to consume available units */
     
        numConsumed = 0;
        done = 0;
     
        for (;;) {
            s = pthread_mutex_lock(&mtx);
            if (s != 0)
                 printf("pthread_mutex_lock");
     
            while (avail == 0) {            /* Wait for something to consume */
                s = pthread_cond_wait(&cond, &mtx);
                if (s != 0)
                     printf("pthread_cond_wait");
            }
     
            /* At this point, 'mtx' is locked... */
     
            while (avail > 0) {             /* Consume all available units */
     
                /* Do something with produced unit */
     
                numConsumed ++;
                avail--;
                printf("T=%ld: numConsumed=%d\n", (long) (time(NULL) - t),
                        numConsumed);
     
                done = numConsumed >= totRequired;
            }
     
            s = pthread_mutex_unlock(&mtx);
            if (s != 0)
                 printf("pthread_mutex_unlock");
     
            if (done)
                break;
            /* Perhaps do other work here that does not require mutex lock */
        }
     
        return 0;
    }
    Reference
    Richard Stones adn Neil Matthew, Begin Linux Programming, 2nd Edition
    Michael Kerrisk, The programming interface, 2010


    Không có nhận xét nào:

    Đăng nhận xét