互斥锁

多任务下载示例:

  1. #include <pthread.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #define NUM_OF_TASKS 5
  5. void *downloadfile(void *filename)
  6. {
  7. printf("I am downloading the file %s!\n", (char *)filename);
  8. sleep(10);
  9. long downloadtime = rand()%100;
  10. printf("I finish downloading the file within %d minutes!\n", downloadtime);
  11. pthread_exit((void *)downloadtime);
  12. }
  13. int main(int argc, char *argv[])
  14. {
  15. char files[NUM_OF_TASKS][20]={"file1.avi","file2.rmvb","file3.mp4","file4.wmv","file5.flv"};
  16. pthread_t threads[NUM_OF_TASKS];
  17. int rc;
  18. int t;
  19. int downloadtime;
  20. pthread_attr_t thread_attr;
  21. pthread_attr_init(&thread_attr);
  22. pthread_attr_setdetachstate(&thread_attr,PTHREAD_CREATE_JOINABLE);
  23. for(t=0;t<NUM_OF_TASKS;t++){
  24. printf("creating thread %d, please help me to download %s\n", t, files[t]);
  25. rc = pthread_create(&threads[t], &thread_attr, downloadfile, (void *)files[t]);
  26. if (rc){
  27. printf("ERROR; return code from pthread_create() is %d\n", rc);
  28. exit(-1);
  29. }
  30. }
  31. pthread_attr_destroy(&thread_attr);
  32. for(t=0;t<NUM_OF_TASKS;t++){
  33. pthread_join(threads[t],(void**)&downloadtime);
  34. printf("Thread %d downloads the file %s in %d minutes.\n",t,files[t],downloadtime);
  35. }
  36. pthread_exit(NULL);
  37. }

一个运行中的线程可以调用 pthread_exit 退出线程。这个函数可以传入一个参数转换为(void *) 类型。这是线程退出的返回值。

接下来,我们来看主线程。在这里面,我列了五个文件名。接下来声明了一个数组,里面有五个 pthread_t 类型的线程对象。

接下来,声明一个线程属性 pthread_attr_t。我们通过 pthread_attr_init 初始化这个属性,并且设置属性 PTHREAD_CREATE_JOINABLE。这表示将来主线程程等待这个线程的结束,并获取退出时的状态。

接下来是一个循环。对于每一个文件和每一个线程,可以调用 pthread_create 创建线程。一共有四个参数,第一个参数是线程对象,第二个参数是线程的属性,第三个参数是线程运行函数,第四个参数是线程运行函数的参数。主线程就是通过第四个参数,将自己的任务派给子线程。

任务分配完毕,每个线程下载一个文件,接下来主线程要做的事情就是等待这些子任务完成。当一个线程退出的时候,就会发送信号给其他所有同进程的线程。有一个线程使用 pthread_join 获取这个线程退出的返回值。线程的返回值通过 pthread_join 传给主线程,这样子线程就将自己下载文件所耗费的时间,告诉给主线程。

好了,程序写完了,开始编译。多线程程序要依赖于 libpthread.so。

  1. gcc download.c -lpthread

条件变量

  1. #include <pthread.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #define NUM_OF_TASKS 3
  5. #define MAX_TASK_QUEUE 11
  6. char tasklist[MAX_TASK_QUEUE]="ABCDEFGHIJ";
  7. int head = 0;
  8. int tail = 0;
  9. int quit = 0;
  10. pthread_mutex_t g_task_lock;
  11. pthread_cond_t g_task_cv;
  12. void *coder(void *notused)
  13. {
  14. pthread_t tid = pthread_self();
  15. while(!quit){
  16. pthread_mutex_lock(&g_task_lock);
  17. while(tail == head){
  18. if(quit){
  19. pthread_mutex_unlock(&g_task_lock);
  20. pthread_exit((void *)0);
  21. }
  22. printf("No task now! Thread %u is waiting!\n", (unsigned int)tid);
  23. pthread_cond_wait(&g_task_cv, &g_task_lock);
  24. printf("Have task now! Thread %u is grabing the task !\n", (unsigned int)tid);
  25. }
  26. char task = tasklist[head++];
  27. pthread_mutex_unlock(&g_task_lock);
  28. printf("Thread %u has a task %c now!\n", (unsigned int)tid, task);
  29. sleep(5);
  30. printf("Thread %u finish the task %c!\n", (unsigned int)tid, task);
  31. }
  32. pthread_exit((void *)0);
  33. }
  34. int main(int argc, char *argv[])
  35. {
  36. pthread_t threads[NUM_OF_TASKS];
  37. int rc;
  38. int t;
  39. pthread_mutex_init(&g_task_lock, NULL);
  40. pthread_cond_init(&g_task_cv, NULL);
  41. for(t=0;t<NUM_OF_TASKS;t++){
  42. rc = pthread_create(&threads[t], NULL, coder, NULL);
  43. if (rc){
  44. printf("ERROR; return code from pthread_create() is %d\n", rc);
  45. exit(-1);
  46. }
  47. }
  48. sleep(5);
  49. for(t=1;t<=4;t++){
  50. pthread_mutex_lock(&g_task_lock);
  51. tail+=t;
  52. printf("I am Boss, I assigned %d tasks, I notify all coders!\n", t);
  53. pthread_cond_broadcast(&g_task_cv);
  54. pthread_mutex_unlock(&g_task_lock);
  55. sleep(20);
  56. }
  57. pthread_mutex_lock(&g_task_lock);
  58. quit = 1;
  59. pthread_cond_broadcast(&g_task_cv);
  60. pthread_mutex_unlock(&g_task_lock);
  61. pthread_mutex_destroy(&g_task_lock);
  62. pthread_cond_destroy(&g_task_cv);
  63. pthread_exit(NULL);
  64. }

image.png