技术共享

C语言:高级并发操作(线程)

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

一、线程的概念

线程:进程中的一个实体,是CPU调度和分派的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器、一组寄存器和栈),但它可以与同属一个进程的其他线程共享进程所拥有的全部资源。一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行。线程在运行中呈现间断性。(以上来自《计算机四级教程——操作系统原理》)

谈到线程,就有必要说说进程的定义:进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。(以上来自《计算机四级教程——操作系统原理》)

进程的定义有点绕口,我们看看进程由什么组成:程序、数据和进程控制块。其中程序,对应进程定义中“具有一定独立功能的程序”,但是进程除了程序本身,还需要有数据(可以理解为资源),以及,进程控制块。数据和进程控制块是程序运行时必不可少的资源,程序依赖这些资源进行相应的活动,就是我们说的“进程”了。

进程的两个基本属性:

进程是一个可拥有资源的独立单位;
进程是一个可以独立调度和分派的基本单位。
线程建立之初,就是为了将进程的上述两个属性分开,线程构成了“CPU调度和分派的基本单位”,这样一个进程中可以有很多线程,操作系统对线程进行调度和分派,可以更好地实现进程的并打执行;同时同一个进程下的线程可以共享该进程的全部资源,可以满足同一个进程下不同线程对进程资源的访问。线程的出现,巧妙地将进程的两个属性分开,使得进程可以更好地处理并行执行的需求。

线程就是一个正在运行的函数。posix线程是一套标准,而不是一套实现。还有别的标准如:openmp线程。
线程标识:pthread_t (不知道具体的内容,各家实现不同,linux下是int)
px axm命令 看到进程和线程--代表进程下的线程。 px ax -L查看轻量级线程。        

       int pthread_equal(pthread_t t1, pthread_t t2); 比较两个线程的ID号。相同返回非0,不同返回0.
       pthread_t pthread_self(void); 获取当前线程的线程ID

二、线程的创建

       int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);
线程的调度取决与调度器的策略。

create1.c

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <pthread.h>
  4. #include <string.h>
  5. void* myfunc(void *p)
  6. {
  7. puts("Thread is run!");
  8. printf("thread %ld n",pthread_self());
  9. return NULL;
  10. }
  11. int main()
  12. {
  13. puts("Begin!");
  14. pthread_t tid;
  15. int ret;
  16. ret = pthread_create(&tid,NULL,myfunc ,NULL);
  17. if(ret)
  18. {
  19. fprintf(stderr,"%s n",strerror(ret));
  20. exit(1);
  21. }
  22. printf("main %ld n",pthread_self());
  23. puts("End!");
  24. }

线程的终止

        1.线程从启动例程返回,返回值就是线程的退出码。
        2. 线程可以被同一进程中的其他线程取消。
        3.线程调用pthread_exit()函数。       void pthread_exit(void *retval);

       int pthread_join(pthread_t thread, void **retval); 相当于进程的wait,用于收尸。

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <pthread.h>
  4. #include <string.h>
  5. void* myfunc(void *p)
  6. {
  7. puts("Thread is run!");
  8. pthread_exit(NULL);//线程专用清理函数。
  9. // return NULL;
  10. }
  11. int main()
  12. {
  13. puts("Begin!");
  14. pthread_t tid;
  15. int ret;
  16. ret = pthread_create(&tid,NULL,myfunc ,NULL);
  17. if(ret)
  18. {
  19. fprintf(stderr,"%s n",strerror(ret));
  20. exit(1);
  21. }
  22. pthread_join(tid,NULL); //收尸
  23. puts("End!");
  24. }

栈的清理

pthread_cleanup_push(); //相当于atexit
pthread_cleanup_pop(); //相当于可以主动取数据。

       void pthread_cleanup_push(void (*routine)(void *),  是宏的实现,gcc -E查看预处理
                                 void *arg);
       void pthread_cleanup_pop(int execute); //选择是否调用。必须成对出现,用宏实现

cleanup.c

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <pthread.h>
  4. #include <string.h>
  5. void cleanup_fun(void*p)
  6. {
  7. puts(p);
  8. }
  9. void* myfunc(void *p)
  10. {
  11. puts("Thread is run!");
  12. pthread_cleanup_push(cleanup_fun,"cleanup:1");
  13. pthread_cleanup_push(cleanup_fun,"cleanup:2");
  14. pthread_cleanup_push(cleanup_fun,"cleanup:3");
  15. puts("push over!");
  16. pthread_exit(NULL);//线程专用清理函数。
  17. // return NULL;
  18. pthread_cleanup_pop(1) //线程退出后,全部都会调用;
  19. pthread_cleanup_pop(0);
  20. pthread_cleanup_pop(1);
  21. }
  22. int main()
  23. {
  24. puts("Begin!");
  25. pthread_t tid;
  26. int ret;
  27. ret = pthread_create(&tid,NULL,myfunc ,NULL);
  28. if(ret)
  29. {
  30. fprintf(stderr,"%s n",strerror(ret));
  31. exit(1);
  32. }
  33. pthread_join(tid,NULL); //收尸
  34. puts("End!");
  35. }

线程的取消选项

正在运行的线程要是想要收尸收回来,那么就需要先进行取消(pthread_cancel)在进行收尸(pthread_join)。

       线程取消:int pthread_cancel(pthread_t thread);
        取消有两种状态:允许和不允许。
        不允许取消:继续执行代码,不受任何影响。
        允许取消又分为:异步cancel,和推迟cancel(默认)->推迟到cancel点在响应。
        cancal点:Posix定义的cancel点,都是可能引发堵塞的系统调用。
        pthread_setcancelstate:可以设置取消状态。
        pthread_setcanceltype:可以设置取消方式。
        pthread_testcancel:函数什么都不做,就是取消点。

线程分离:       int pthread_detach(pthread_t thread);

  动态模块单次初始化函数:int pthread_once(pthread_once_t *once_control,
           void (*init_routine)(void));
       pthread_once_t once_control = PTHREAD_ONCE_INIT;
 

     实例1
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <pthread.h>
  6. #define LEFT 30000000
  7. #define RIGHT 30000200
  8. #define THRNUM (RIGHT-LEFT+1)
  9. void* thr_prime(void*p);
  10. int main()
  11. {
  12. pthread_t tid[THRNUM];
  13. int i,j,mark;
  14. int err;
  15. for(i =LEFT;i<=RIGHT;i++)
  16. {
  17. err= pthread_create(tid+(i-LEFT),NULL,thr_prime,&i);
  18. if(err)
  19. {
  20. fprintf(stderr,"pthread_create():%sn",strerror(err));
  21. }
  22. }
  23. for(i=LEFT;i<=RIGHT;i++)
  24. {
  25. pthread_join(tid[i-LEFT],NULL);
  26. }
  27. return 0;
  28. }
  29. void* thr_prime(void*p)
  30. {
  31. int i,j,mark;
  32. i = *(int*)p;
  33. mark = 1;
  34. for(j=2;j<i/2;j++)
  35. {
  36. if(i%j ==0)
  37. {
  38. mark = 0;
  39. break;
  40. }
  41. }
  42. if(mark)
  43. printf("%d is a primer n",i);
  44. pthread_exit(NULL);
  45. return NULL;
  46. }

以上代码运行会出现竞争的现象。因为传递参数用的是地址传参,数据需要取*才能拿到,不能保证上一个线程是否进行了该操作,最简单的是使用值传递。

primer0.c

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <pthread.h>
  6. #define LEFT 30000000
  7. #define RIGHT 30000200
  8. #define THRNUM (RIGHT-LEFT+1)
  9. void* thr_prime(void*p);
  10. int main()
  11. {
  12. pthread_t tid[THRNUM];
  13. int i,j,mark;
  14. int err;
  15. for(i =LEFT;i<=RIGHT;i++)
  16. {
  17. err= pthread_create(tid+(i-LEFT),NULL,thr_prime,(void *)i);
  18. // err= pthread_create(tid+(i-LEFT),NULL,thr_prime,&i);
  19. if(err)
  20. {
  21. fprintf(stderr,"pthread_create():%sn",strerror(err));
  22. }
  23. }
  24. for(i=LEFT;i<=RIGHT;i++)
  25. {
  26. pthread_join(tid[i-LEFT],NULL);
  27. }
  28. return 0;
  29. }
  30. void* thr_prime(void*p)
  31. {
  32. int i,j,mark;
  33. i = (int)p;
  34. // i = *(int*)p;
  35. mark = 1;
  36. for(j=2;j<i/2;j++)
  37. {
  38. if(i%j ==0)
  39. {
  40. mark = 0;
  41. break;
  42. }
  43. }
  44. if(mark)
  45. printf("%d is a primer n",i);
  46. pthread_exit(NULL);
  47. return NULL;
  48. }

 primer0_e.c

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <pthread.h>
  6. #define LEFT 30000000
  7. #define RIGHT 30000200
  8. #define THRNUM (RIGHT-LEFT+1)
  9. struct thr_arg_st
  10. {
  11. int n;
  12. };
  13. void* thr_prime(void*p);
  14. int main()
  15. {
  16. pthread_t tid[THRNUM];
  17. int i,j,mark;
  18. int err;
  19. struct thr_arg_st* p;
  20. void *ptr;
  21. for(i =LEFT;i<=RIGHT;i++)
  22. {
  23. p = malloc(sizeof(*p));
  24. if(p ==NULL)
  25. {
  26. perror("malloc");
  27. exit(1);
  28. }
  29. p->n = i;
  30. err= pthread_create(tid+(i-LEFT),NULL,thr_prime,p); // p就是结构体指针就是n的地址
  31. // err= pthread_create(tid+(i-LEFT),NULL,thr_prime,&i);
  32. if(err)
  33. {
  34. fprintf(stderr,"pthread_create():%sn",strerror(err));
  35. }
  36. //free 不能在这里free,必须取走数据在free
  37. }
  38. for(i=LEFT;i<=RIGHT;i++)
  39. {
  40. pthread_join(tid[i-LEFT],&ptr);// 收尸并且接受返回参数。
  41. free(ptr);
  42. }
  43. return 0;
  44. }
  45. void* thr_prime(void*p)
  46. {
  47. int i,j,mark;
  48. i = ((struct thr_arg_st*)p)->n;
  49. mark = 1;
  50. for(j=2;j<i/2;j++)
  51. {
  52. if(i%j ==0)
  53. {
  54. mark = 0;
  55. break;
  56. }
  57. }
  58. if(mark)
  59. printf("%d is a primer n",i);
  60. pthread_exit(p); //返回值返回p
  61. return NULL;
  62. }
实例2 

add.c

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <pthread.h>
  6. #define FILENAME "/tmp/out"
  7. #define THRNUM (20)
  8. void* thr_add(void*p);
  9. int main()
  10. {
  11. pthread_t tid[THRNUM];
  12. int i,j,mark;
  13. int err;
  14. for(i =0;i<=THRNUM;i++)
  15. {
  16. err= pthread_create(tid+(i),NULL,thr_add,NULL);
  17. if(err)
  18. {
  19. fprintf(stderr,"pthread_create():%sn",strerror(err));
  20. }
  21. }
  22. for(i=0;i<=THRNUM;i++)
  23. {
  24. pthread_join(tid[i],NULL);
  25. }
  26. return 0;
  27. }
  28. void* thr_add(void*p)
  29. {
  30. FILE*fp;
  31. char line_buf[1024];
  32. int len_size = 1024;
  33. fp = fopen(FILENAME,"r+");
  34. fgets(line_buf,len_size,fp);
  35. fseek(fp,0,SEEK_SET);
  36. fprintf(fp,"%d n",atoi(line_buf)+1);
  37. fclose(fp);
  38. pthread_exit(NULL);
  39. return NULL;
  40. }

二十个线程同时在一个文件中读数据写数据时会出现竞争和冲突。一个线程还没有写进入时,另一个线程读到了上次的数据。 

mytbf.c
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <error.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8. #include <fcntl.h>
  9. #include <errno.h>
  10. #include <signal.h>
  11. #include <pthread.h>
  12. #include "mytbf.h"
  13. struct mytbf_st
  14. {
  15. int cps;
  16. int burst;
  17. int token;
  18. int pos;
  19. pthread_mutex_t mut;
  20. };
  21. static pthread_mutex_t mut_job = PTHREAD_MUTEX_INITIALIZER;
  22. static pthread_t tid_alrm;
  23. pthread_once_t init_once = PTHREAD_ONCE_INIT;
  24. static struct mytbf_st* job[MYTBF_MAX];
  25. typedef void (*sighandler_t)(int);
  26. static int get_free_pos_unlocked(void)
  27. {
  28. for(int i=0;i< MYTBF_MAX;i++)
  29. {
  30. if(job[i]==NULL)
  31. return i;
  32. }
  33. return -1;
  34. }
  35. static void* thr_alrm(void*p)
  36. {
  37. while(1)
  38. {
  39. pthread_mutex_lock(&mut_job);
  40. for(int i=0;i<MYTBF_MAX;i++)
  41. {
  42. if(job[i] != NULL)
  43. {
  44. pthread_mutex_lock(&job[i]->mut);
  45. job[i]->token += job[i]->cps;
  46. if(job[i]->token >job[i]->burst )
  47. {
  48. job[i]->token = job[i]->burst;
  49. }
  50. pthread_mutex_unlock(&job[i]->mut);
  51. }
  52. }
  53. pthread_mutex_unlock(&mut_job);
  54. sleep(1);
  55. }
  56. return NULL;
  57. }
  58. static void module_unload()
  59. {
  60. pthread_cancel(tid_alrm);
  61. pthread_join(tid_alrm,NULL);
  62. //只能一个人掉,二个人调用容易出差
  63. for(int i=0;i<MYTBF_MAX;i++)
  64. {
  65. if(job[i]!=NULL)
  66. {
  67. mytbf_destroy(job[i]);
  68. }
  69. }
  70. pthread_mutex_destroy(&mut_job);
  71. }
  72. static void module_load()
  73. {
  74. int err;
  75. err = pthread_create(&tid_alrm,NULL,thr_alrm,NULL);
  76. if(err)
  77. {
  78. fprintf(stderr,"create errorn");
  79. exit(1);
  80. }
  81. atexit(module_unload);
  82. }
  83. mytbf_t* mytbf_init(int cps ,int burst) //C语言中,void*可以赋值给任何类型的指针,任何类型的指针也都可以赋值给void*
  84. {
  85. struct mytbf_st*me;
  86. int pos;
  87. pthread_once(&init_once,module_load); //只初始化一次
  88. me = malloc(sizeof(*me));
  89. if(me == NULL)
  90. return NULL;
  91. me->cps = cps;
  92. me->burst = burst;
  93. me->token = 0;
  94. pthread_mutex_init(&me->mut,NULL);
  95. pthread_mutex_lock(&mut_job);
  96. pos = get_free_pos_unlocked();
  97. if(pos < 0)
  98. {
  99. pthread_mutex_unlock(&mut_job);
  100. free(me);
  101. return NULL;
  102. }
  103. me->pos = pos;
  104. job[pos] = me;
  105. pthread_mutex_unlock(&mut_job);
  106. return me;
  107. }
  108. int mytbf_fetchtoken(mytbf_t*ptr,int size) //获取token
  109. {
  110. if(size <= 0)
  111. return -EINVAL; //参数非法
  112. struct mytbf_st*me = ptr;
  113. pthread_mutex_lock(&me->mut);
  114. while(me->token <= 0 ) //token为空就等待
  115. {
  116. pthread_mutex_unlock(&me->mut);
  117. sched_yield();
  118. pthread_mutex_lock(&me->mut);
  119. }
  120. int n = (me->token>size?size:me->token);
  121. me->token -= n;
  122. pthread_mutex_unlock(&me->mut);
  123. return n;
  124. }
  125. int mytbf_returntoken(mytbf_t*ptr,int size) //返还token
  126. {
  127. if(size<=0)
  128. return -EINVAL;
  129. struct mytbf_st*me = ptr;
  130. pthread_mutex_lock(&me->mut);
  131. me->token+= size;
  132. if(me->token > me->burst)
  133. me->token = me->burst;
  134. pthread_mutex_unlock(&me->mut);
  135. return size;
  136. }
  137. int mytbf_destroy(mytbf_t*ptr)
  138. {
  139. struct mytbf_st *me;
  140. me = ptr;
  141. pthread_mutex_lock(&mut_job);
  142. job[me->pos] = NULL;
  143. pthread_mutex_unlock(&mut_job);
  144. pthread_mutex_destroy(&me->mut);
  145. free(ptr);
  146. return 0;
  147. }

三、线程同步

互斥量

相当于一把锁,必须先进行解锁才能操作。(查询法)
如果man pthread_mutex_init报错,请安装依赖:
sudo apt-get install manpages-posix manpages-posix-dev

       int pthread_mutex_destroy(pthread_mutex_t *mutex); //销毁锁
       int pthread_mutex_init(pthread_mutex_t *restrict mutex, 
           const pthread_mutexattr_t *restrict attr);  动态初始化
       pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;  静态初始化

       int pthread_mutex_lock(pthread_mutex_t *mutex); //加锁
       int pthread_mutex_trylock(pthread_mutex_t *mutex);//尝试加锁,抢不上就继续执行
       int pthread_mutex_unlock(pthread_mutex_t *mutex);//解锁

add.c

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <pthread.h>
  6. #define FILENAME "/tmp/out"
  7. #define THRNUM (20)
  8. pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
  9. void* thr_add(void*p);
  10. int main()
  11. {
  12. pthread_t tid[THRNUM];
  13. int i,j,mark;
  14. int err;
  15. for(i =0;i<THRNUM;i++)
  16. {
  17. err= pthread_create(tid+(i),NULL,thr_add,NULL);
  18. if(err)
  19. {
  20. fprintf(stderr,"pthread_create():%sn",strerror(err));
  21. }
  22. }
  23. for(i=0;i<THRNUM;i++)
  24. {
  25. pthread_join(tid[i],NULL);
  26. }
  27. pthread_mutex_destroy(&mut);
  28. return 0;
  29. }
  30. void* thr_add(void*p)
  31. {
  32. FILE*fp;
  33. char line_buf[1024];
  34. int len_size = 1024;
  35. pthread_mutex_lock(&mut);
  36. fp = fopen(FILENAME,"r+");
  37. fgets(line_buf,len_size,fp);
  38. fseek(fp,0,SEEK_SET);
  39. fprintf(fp,"%d n",atoi(line_buf)+1);
  40. fclose(fp);
  41. pthread_mutex_unlock(&mut);
  42. pthread_exit(NULL);
  43. return NULL;
  44. }

abcd.c

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <pthread.h>
  6. #define FILENAME "/tmp/out"
  7. #define THRNUM (4)
  8. pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
  9. void* thr_abcd(void*p);
  10. int main()
  11. {
  12. pthread_t tid[THRNUM];
  13. int i,j,mark;
  14. int err;
  15. for(i =0;i<THRNUM;i++)
  16. {
  17. err= pthread_create(tid+(i),NULL,thr_abcd,(void*)i);
  18. if(err)
  19. {
  20. fprintf(stderr,"pthread_create():%sn",strerror(err));
  21. }
  22. }
  23. alarm(2);
  24. for(i=0;i<THRNUM;i++)
  25. {
  26. pthread_join(tid[i],NULL);
  27. }
  28. pthread_mutex_destroy(&mut);
  29. return 0;
  30. }
  31. void* thr_abcd(void*p)
  32. {
  33. int c = 'a'+ (int)p;
  34. while(1)
  35. {
  36. write(1,&c,1);
  37. }
  38. pthread_exit(NULL);
  39. return NULL;
  40. }

 abcd.c
使用锁链进行加锁解锁。

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <pthread.h>
  6. #define FILENAME "/tmp/out"
  7. #define THRNUM (4)
  8. pthread_mutex_t mut[THRNUM];
  9. void* thr_abcd(void*p);
  10. int main()
  11. {
  12. pthread_t tid[THRNUM];
  13. int i,j,mark;
  14. int err;
  15. for(i =0;i<THRNUM;i++)
  16. {
  17. pthread_mutex_init(mut+i,NULL); //初始化四个锁
  18. pthread_mutex_lock(mut+i);
  19. err= pthread_create(tid+(i),NULL,thr_abcd,(void*)i);
  20. if(err)
  21. {
  22. fprintf(stderr,"pthread_create():%sn",strerror(err));
  23. }
  24. }
  25. pthread_mutex_unlock(mut+0);
  26. alarm(2);
  27. for(i=0;i<THRNUM;i++)
  28. {
  29. pthread_join(tid[i],NULL);
  30. }
  31. pthread_mutex_destroy(&mut);
  32. return 0;
  33. }
  34. int next(int n)
  35. {
  36. if(n +1 ==THRNUM)
  37. return 0;
  38. return n+1;
  39. }
  40. void* thr_abcd(void*p)
  41. {
  42. int c = 'a'+ (int)p;
  43. int n = (int)p;
  44. while(1)
  45. {
  46. pthread_mutex_lock(mut+n);
  47. write(1,&c,1);
  48. pthread_mutex_unlock(mut+next(n) );
  49. }
  50. pthread_exit(NULL);
  51. return NULL;
  52. }

 池类算法实现算质数(查询法)

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <pthread.h>
  6. #define LEFT 30000000
  7. #define RIGHT 30000200
  8. #define THRNUM (RIGHT-LEFT+1)
  9. void* thr_prime(void*p);
  10. int main()
  11. {
  12. pthread_t tid[THRNUM];
  13. int i,j,mark;
  14. int err;
  15. for(i =LEFT;i<=RIGHT;i++)
  16. {
  17. err= pthread_create(tid+(i-LEFT),NULL,thr_prime,(void *)i);
  18. // err= pthread_create(tid+(i-LEFT),NULL,thr_prime,&i);
  19. if(err)
  20. {
  21. fprintf(stderr,"pthread_create():%sn",strerror(err));
  22. }
  23. }
  24. for(i=LEFT;i<=RIGHT;i++)
  25. {
  26. pthread_join(tid[i-LEFT],NULL);
  27. }
  28. return 0;
  29. }
  30. void* thr_prime(void*p)
  31. {
  32. int i,j,mark;
  33. i = (int)p;
  34. // i = *(int*)p;
  35. mark = 1;
  36. for(j=2;j<i/2;j++)
  37. {
  38. if(i%j ==0)
  39. {
  40. mark = 0;
  41. break;
  42. }
  43. }
  44. if(mark)
  45. printf("%d is a primer n",i);
  46. pthread_exit(NULL);
  47. return NULL;
  48. }

 条件变量

通知法进行通信。

   int pthread_cond_destroy(pthread_cond_t *cond);
       int pthread_cond_init(pthread_cond_t *restrict cond, 
           const pthread_condattr_t *restrict attr);
       pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
       int pthread_cond_broadcast(pthread_cond_t *cond); //叫醒所有的等待
       int pthread_cond_signal(pthread_cond_t *cond);//叫醒任意一个等待
       int pthread_cond_timedwait(pthread_cond_t *restrict cond, //超时等待
           pthread_mutex_t *restrict mutex,
           const struct timespec *restrict abstime);
       int pthread_cond_wait(pthread_cond_t *restrict cond, //死等
           pthread_mutex_t *restrict mutex);

mytbf.c(通知法)

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <error.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8. #include <fcntl.h>
  9. #include <errno.h>
  10. #include <signal.h>
  11. #include <pthread.h>
  12. #include "mytbf.h"
  13. struct mytbf_st
  14. {
  15. int cps;
  16. int burst;
  17. int token;
  18. int pos;
  19. pthread_mutex_t mut;
  20. pthread_cond_t cond;
  21. };
  22. static pthread_mutex_t mut_job = PTHREAD_MUTEX_INITIALIZER;
  23. static pthread_t tid_alrm;
  24. pthread_once_t init_once = PTHREAD_ONCE_INIT;
  25. static struct mytbf_st* job[MYTBF_MAX];
  26. typedef void (*sighandler_t)(int);
  27. static int get_free_pos_unlocked(void)
  28. {
  29. for(int i=0;i< MYTBF_MAX;i++)
  30. {
  31. if(job[i]==NULL)
  32. return i;
  33. }
  34. return -1;
  35. }
  36. static void* thr_alrm(void*p)
  37. {
  38. while(1)
  39. {
  40. pthread_mutex_lock(&mut_job);
  41. for(int i=0;i<MYTBF_MAX;i++)
  42. {
  43. if(job[i] != NULL)
  44. {
  45. pthread_mutex_lock(&job[i]->mut);
  46. job[i]->token += job[i]->cps;
  47. if(job[i]->token >job[i]->burst )
  48. {
  49. job[i]->token = job[i]->burst;
  50. }
  51. pthread_cond_broadcast(&job[i]->cond);
  52. pthread_mutex_unlock(&job[i]->mut);
  53. }
  54. }
  55. pthread_mutex_unlock(&mut_job);
  56. sleep(1);
  57. }
  58. return NULL;
  59. }
  60. static void module_unload()
  61. {
  62. pthread_cancel(tid_alrm);
  63. pthread_join(tid_alrm,NULL);
  64. //只能一个人掉,二个人调用容易出差
  65. for(int i=0;i<MYTBF_MAX;i++)
  66. {
  67. if(job[i]!=NULL)
  68. {
  69. mytbf_destroy(job[i]);
  70. }
  71. }
  72. pthread_mutex_destroy(&mut_job);
  73. }
  74. static void module_load()
  75. {
  76. int err;
  77. err = pthread_create(&tid_alrm,NULL,thr_alrm,NULL);
  78. if(err)
  79. {
  80. fprintf(stderr,"create errorn");
  81. exit(1);
  82. }
  83. atexit(module_unload);
  84. }
  85. mytbf_t* mytbf_init(int cps ,int burst) //C语言中,void*可以赋值给任何类型的指针,任何类型的指针也都可以赋值给void*
  86. {
  87. struct mytbf_st*me;
  88. int pos;
  89. pthread_once(&init_once,module_load); //只初始化一次
  90. me = malloc(sizeof(*me));
  91. if(me == NULL)
  92. return NULL;
  93. me->cps = cps;
  94. me->burst = burst;
  95. me->token = 0;
  96. pthread_mutex_init(&me->mut,NULL);
  97. pthread_cond_init(&me->cond,NULL);
  98. pthread_mutex_lock(&mut_job);
  99. pos = get_free_pos_unlocked();
  100. if(pos < 0)
  101. {
  102. pthread_mutex_unlock(&mut_job);
  103. free(me);
  104. return NULL;
  105. }
  106. me->pos = pos;
  107. job[pos] = me;
  108. pthread_mutex_unlock(&mut_job);
  109. return me;
  110. }
  111. int mytbf_fetchtoken(mytbf_t*ptr,int size) //获取token
  112. {
  113. if(size <= 0)
  114. return -EINVAL; //参数非法
  115. struct mytbf_st*me = ptr;
  116. pthread_mutex_lock(&me->mut);
  117. while(me->token <= 0 ) //token为空就等待
  118. {
  119. pthread_cond_wait(&me->cond,&me->mut); //解锁等待,等待conad_broadcast和conad_signal的到来
  120. /*
  121. pthread_mutex_unlock(&me->mut);
  122. sched_yield();
  123. pthread_mutex_lock(&me->mut);
  124. */
  125. }
  126. int n = (me->token>size?size:me->token);
  127. me->token -= n;
  128. pthread_mutex_unlock(&me->mut);
  129. return n;
  130. }
  131. int mytbf_returntoken(mytbf_t*ptr,int size) //返还token
  132. {
  133. if(size<=0)
  134. return -EINVAL;
  135. struct mytbf_st*me = ptr;
  136. pthread_mutex_lock(&me->mut);
  137. me->token+= size;
  138. if(me->token > me->burst)
  139. me->token = me->burst;
  140. pthread_cond_broadcast(&me->cond);
  141. pthread_mutex_unlock(&me->mut);
  142. return size;
  143. }
  144. int mytbf_destroy(mytbf_t*ptr)
  145. {
  146. struct mytbf_st *me;
  147. me = ptr;
  148. pthread_mutex_lock(&mut_job);
  149. job[me->pos] = NULL;
  150. pthread_mutex_unlock(&mut_job);
  151. pthread_mutex_destroy(&me->mut);
  152. pthread_cond_destroy(&me->cond);
  153. free(ptr);
  154. return 0;
  155. }

 primer0_pool.c

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <pthread.h>
  6. #include <sched.h>
  7. #define LEFT 30000000
  8. #define RIGHT 30000200
  9. #define THRNUM (4)
  10. static int num = 0;
  11. static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
  12. static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
  13. void* thr_prime(void*p);
  14. int main()
  15. {
  16. pthread_t tid[THRNUM];
  17. int i,j,mark;
  18. int err;
  19. for(i =0;i<=THRNUM;i++)
  20. {
  21. err= pthread_create(tid+(i),NULL,thr_prime,(void *)i);
  22. if(err)
  23. {
  24. fprintf(stderr,"pthread_create():%sn",strerror(err));
  25. }
  26. }
  27. //下发任务
  28. for(i=LEFT;i<RIGHT;i++)
  29. {
  30. pthread_mutex_lock(&mut);
  31. while(num !=0) //不是0就需要等待任务被取走
  32. {
  33. pthread_cond_wait(&cond,&mut);
  34. }
  35. num = i; //下发任务
  36. pthread_cond_signal(&cond); //下游叫醒任意一个
  37. pthread_mutex_unlock(&mut);
  38. }
  39. pthread_mutex_lock(&mut);
  40. while(num!= 0)
  41. {
  42. pthread_mutex_unlock(&mut);
  43. sched_yield(); //出让调度器给别的线程
  44. }
  45. num = -1; //用于线程退出
  46. pthread_cond_broadcast(&cond);
  47. pthread_mutex_unlock(&mut);
  48. for(i=0;i<=THRNUM;i++)
  49. {
  50. pthread_join(tid[i],NULL);
  51. }
  52. pthread_mutex_destroy(&mut);
  53. pthread_cond_destroy(&cond);
  54. return 0;
  55. }
  56. void* thr_prime(void*p)
  57. {
  58. int i,j,mark;
  59. while(1)
  60. {
  61. pthread_mutex_lock(&mut);
  62. while(num == 0)
  63. {
  64. pthread_cond_wait(&cond,&mut);
  65. }
  66. if(num == -1)
  67. {
  68. pthread_mutex_unlock(&mut); //走到这里必须要解锁。
  69. break;
  70. }
  71. i= num;
  72. num = 0;
  73. pthread_cond_broadcast(&cond);
  74. pthread_mutex_unlock(&mut);
  75. mark = 1;
  76. for(j=2;j<i/2;j++)
  77. {
  78. if(i%j ==0)
  79. {
  80. mark = 0;
  81. break;
  82. }
  83. }
  84. if(mark)
  85. printf("[%d]%d is a primer n",(int)p,i);
  86. }
  87. pthread_exit(NULL);
  88. return NULL;
  89. }

abcd_cond.c

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <pthread.h>
  6. #define FILENAME "/tmp/out"
  7. #define THRNUM (4)
  8. pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
  9. pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
  10. int num;
  11. void* thr_abcd(void*p);
  12. int main()
  13. {
  14. pthread_t tid[THRNUM];
  15. int i,j,mark;
  16. int err;
  17. for(i =0;i<THRNUM;i++)
  18. {
  19. err= pthread_create(tid+(i),NULL,thr_abcd,(void*)i);
  20. if(err)
  21. {
  22. fprintf(stderr,"pthread_create():%sn",strerror(err));
  23. }
  24. }
  25. alarm(2);
  26. for(i=0;i<THRNUM;i++)
  27. {
  28. pthread_join(tid[i],NULL);
  29. }
  30. pthread_cond_destroy(&cond);
  31. pthread_mutex_destroy(&mut);
  32. return 0;
  33. }
  34. int next(int n)
  35. {
  36. if(n +1 ==THRNUM)
  37. return 0;
  38. return n+1;
  39. }
  40. void* thr_abcd(void*p)
  41. {
  42. int c = 'a'+ (int)p;
  43. int n = (int)p;
  44. while(1)
  45. {
  46. pthread_mutex_lock(&mut);
  47. while(num != n)
  48. {
  49. pthread_cond_wait(&cond,&mut);
  50. }
  51. write(1,&c,1);
  52. num = next(num);
  53. pthread_cond_broadcast(&cond);
  54. pthread_mutex_unlock(&mut );
  55. }
  56. pthread_exit(NULL);
  57. return NULL;
  58. }

 信号量

互斥量是bool类型,信号量(semaphore)是int类型,使用的时候进行自减,不够就等待。

mysem.c

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <pthread.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include "mysem.h"
  7. struct mysem_st
  8. {
  9. int value;
  10. pthread_mutex_t mut;
  11. pthread_cond_t cond;
  12. };
  13. mysem_t* mysem_init(int initval)
  14. {
  15. struct mysem_st*me;
  16. me = malloc(sizeof(*me));
  17. if(me==NULL)
  18. return NULL;
  19. me->value = initval;
  20. pthread_mutex_init(&me->mut,NULL);
  21. pthread_cond_init(&me->cond,NULL);
  22. return me;
  23. }
  24. int mysem_add(mysem_t*ptr ,int n)
  25. {
  26. struct mysem_st*me = ptr;
  27. pthread_mutex_lock(&me->mut);
  28. me->value+= n;
  29. pthread_cond_broadcast(&me->cond);
  30. pthread_mutex_unlock(&me->mut);
  31. return n;
  32. }
  33. int mysem_sub(mysem_t*ptr ,int n )
  34. {
  35. struct mysem_st*me = ptr;
  36. pthread_mutex_lock(&me->mut);
  37. while(me->value <n)
  38. {
  39. pthread_cond_wait(&me->cond,&me->mut);
  40. }
  41. me->value -=n;
  42. pthread_mutex_unlock(&me->mut);
  43. return n;
  44. }
  45. void mysem_destroy(mysem_t*ptr)
  46. {
  47. struct mysem_st*me = ptr;
  48. pthread_mutex_destroy(&me->mut);
  49. pthread_cond_destroy(&me->cond);
  50. free(me);
  51. }

mysem.h 

  1. #ifndef MYSEM_H
  2. #define MYSEM_H
  3. typedef void mysem_t;
  4. mysem_t* mysem_init(int initval);
  5. int mysem_add(mysem_t*,int);
  6. int mysem_sub(mysem_t*,int);
  7. void mysem_destroy(mysem_t*);
  8. #endif

 main.c

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <pthread.h>
  6. #include "mysem.h"
  7. #define LEFT 30000000
  8. #define RIGHT 30000200
  9. #define THRNUM (RIGHT-LEFT+1)
  10. #define N 4
  11. static mysem_t* sem;
  12. void* thr_prime(void*p);
  13. int main()
  14. {
  15. pthread_t tid[THRNUM];
  16. int i,j,mark;
  17. int err;
  18. sem = mysem_init(N);
  19. if(sem ==NULL)
  20. {
  21. fprintf(stderr,"mysem_init n");
  22. exit(1);
  23. }
  24. for(i =LEFT;i<=RIGHT;i++)
  25. {
  26. mysem_sub(sem,1);
  27. err= pthread_create(tid+(i-LEFT),NULL,thr_prime,(void *)i);
  28. if(err)
  29. {
  30. fprintf(stderr,"pthread_create():%sn",strerror(err));
  31. }
  32. }
  33. for(i=LEFT;i<=RIGHT;i++)
  34. {
  35. pthread_join(tid[i-LEFT],NULL);
  36. }
  37. mysem_destroy(sem);
  38. return 0;
  39. }
  40. void* thr_prime(void*p)
  41. {
  42. int i,j,mark;
  43. i = (int)p;
  44. // i = *(int*)p;
  45. mark = 1;
  46. for(j=2;j<i/2;j++)
  47. {
  48. if(i%j ==0)
  49. {
  50. mark = 0;
  51. break;
  52. }
  53. }
  54. if(mark)
  55. printf("%d is a primer n",i);
  56. sleep(5); //ps ax -L 可以观察到对线程进行了限制,只创建了四个线程
  57. mysem_add(sem,1);
  58. pthread_exit(NULL);
  59. return NULL;
  60. }

makefile

  1. all:mysem
  2. CFLAGS+=-g -Wall -pthread
  3. LDFLAGS+= -pthread
  4. mysem:main.o mysem.o
  5. gcc $^ $(CFLAGS) $(LDFLAGS) -o $@
  6. clean:
  7. rm -rf *.o mysem

读写锁

互斥量和信号量的综合使用。分为读锁(信号量)和写锁(互斥量)。一般读写要设置上限。

需要防止写者饿死的情况发生。

四、线程相关属性

pthread_create第二个参数是线程的属性。

       int pthread_attr_init(pthread_attr_t *attr);
       int pthread_attr_destroy(pthread_attr_t *attr);

测试程序创建最大线程个数。()

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <pthread.h>
  4. void* func(void)
  5. {
  6. int i;
  7. // printf("%pn",&i);
  8. pthread_exit(NULL);
  9. return NULL;
  10. }
  11. int main()
  12. {
  13. int err;
  14. pthread_t tid;
  15. pthread_attr_t attr;
  16. pthread_attr_init(&attr);
  17. pthread_attr_setstacksize(&attr,1024*1024); //1mb
  18. int i = 0;
  19. for(;;i++)
  20. {
  21. err = pthread_create(&tid,&attr,func,NULL);
  22. if(err)
  23. {
  24. fprintf(stderr,"create errn");
  25. break;
  26. }
  27. }
  28. printf("max = %d n",i);
  29. pthread_attr_destroy(&attr);
  30. return 0;
  31. }

线程同步的属性

互斥量属性:

       int pthread_mutexattr_init(pthread_mutexattr_t *attr);
       Refer to pthread_mutexattr_destroy().
        int pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, //跨进程起作用
                                        int *pshared);
       int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr,
                                        int pshared);

//创建一个子进程,可以共享文件描述符数组.也可以选择不共享。linux下不区分进程和线程
       int clone(int (*fn)(void *), void *stack, int flags, void *arg, ... 
                 /* pid_t *parent_tid, void *tls, pid_t *child_tid */ );
       int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict attr,
           int *restrict type);
       int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);

条件变量属性:       
       int pthread_condattr_destroy(pthread_condattr_t *attr);
       int pthread_condattr_init(pthread_condattr_t *attr);
读写锁属性:

五、重入

一个可重入的函数简单来说就是可以被中断的函数,也就是说,可以在这个函数执行的任何时刻中断它,转入OS调度下去执行另外一段代码,而返回控制时不会出现什么错误;而不可重入的函数由于使用了一些系统资源,比如全局变量区,中断向量表等,所以它如果被中断的话,可能会出现问题,这类函数是不能运行在多任务环境下的。

多线程中的IO。unlocked函数结尾的都是(不可重入函数,不支持多线程并发)。man putc_unlocked,查看不支持的IO操作。

线程与信号

       int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset);
       int sigwait(const sigset_t *set, int *sig);
       int pthread_kill(pthread_t thread, int sig);

openmp线程标准

参考官网:www.OpenMp.org

gcc4.0之后都支持openmp语法标记。有几个CPU就可以实现多少并发

hello.c

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main()
  4. {
  5. #pragma omp parallel //实现并发
  6. {
  7. puts("Hello ");
  8. puts(" World");
  9. }
  10. return 0;
  11. }

makefile

CFLAGS += -Wall -fopenmp

make hello编译,并且运行。

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <omp.h>
  4. int main()
  5. {
  6. #pragma omp parallel sections
  7. {
  8. #pragma omp section
  9. printf("[%d:]Hello n",omp_get_thread_num() );
  10. #pragma omp section
  11. printf("[%d:]World n",omp_get_thread_num() );
  12. }
  13. return 0;
  14. }