Обмен технологиями

Язык C: расширенные операции параллелизма (потоки)

2024-07-12

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

1. Понятие нити

Тема: Сущность в процессе и базовая единица планирования и диспетчеризации ЦП. Сам поток по сути не владеет системными ресурсами, а лишь несколькими ресурсами, необходимыми для работы (такими как счетчик программ, набор регистров и стек), но он может делиться всеми ресурсами, принадлежащими процессу, с другими потоками. принадлежащие одному и тому же процессу. Поток может создавать и уничтожать другой поток; несколько потоков в одном процессе могут выполняться одновременно. Во время работы потоки демонстрируют прерывистое поведение. (Вышеизложенное взято из «Учебного пособия по компьютерному уровню 4 — Принципы работы операционной системы»).

Когда речь идет о потоках, необходимо поговорить об определении процесса: процесс — это программа с определенными независимыми функциями. Процесс — это независимая единица распределения ресурсов и планирования в системе. (Вышеизложенное взято из «Учебного пособия по компьютерному уровню 4 — Принципы работы операционной системы»).

Определение процесса немного запутанное. Давайте посмотрим, из чего состоит процесс: из программы, данных и блока управления процессом. Среди них программа соответствует «программе с определенными независимыми функциями» в определении процесса. Однако, помимо самой программы, процессу также необходимы данные (которые можно понимать как ресурсы) и блоки управления процессом. Блоки управления данными и процессами являются важными ресурсами во время работы программы. Программа использует эти ресурсы для выполнения соответствующих действий, которые мы называем «процессом».

Два основных свойства процессов:

Процесс — это независимая единица, которая может владеть ресурсами;
Процесс — это базовая единица, которую можно независимо планировать и отправлять.
Когда потоки были впервые созданы, это было необходимо для разделения двух вышеупомянутых атрибутов процесса. Потоки представляют собой «базовую единицу планирования и диспетчеризации ЦП». Таким образом, в процессе может быть много потоков, и операционная система может планировать их. и лучше распределять потоки. Он может реализовать параллельное выполнение процессов; в то же время потоки одного и того же процесса могут совместно использовать все ресурсы процесса, что может удовлетворить доступ к ресурсам процесса различными потоками одного и того же процесса. Появление потоков умело разделяет два атрибута процесса, позволяя процессу лучше справляться с потребностями параллельного выполнения.

Поток — это работающая функция. Потоки POSIX — это набор стандартов, а не набор реализаций. Существуют и другие стандарты, такие как: потоки openmp.
Идентификатор темы: pthread_t (конкретный контент не знаю, каждая компания реализует по-своему, под Linux это int)
Команда px axm видит процессы и потоки, представляющие потоки в рамках процесса. px ax -L для просмотра легких потоков.

int pthread_equal(pthread_t t1, pthread_t t2); Сравните идентификационные номера двух потоков. Если они одинаковы, возвращается ненулевое значение; если они разные, возвращается 0.
pthread_t pthread_self(void); Получить идентификатор текущего потока.

2. Создание тем

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
Планирование потоков зависит от стратегии планировщика.

создать1.с

  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); эквивалентно ожиданию процесса и используется для сбора трупов.

  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); //Выберите, следует ли вызывать.Должны появляться парами, реализованы с помощью макросов.

очистка.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);
Отмена имеет два статуса: разрешена и не разрешена.
Отмена не разрешена: выполнение кода продолжается без изменений.
Разрешенная отмена делится на: асинхронную отмену и отложенную отмену (по умолчанию) -&gt; отложенный ответ до точки отмены.
Точка отмены. Точки отмены, определенные Posix, представляют собой системные вызовы, которые могут вызвать перегрузку.
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

добавить.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. }

3. Синхронизация потоков

мьютекс

Он эквивалентен замку и должен быть разблокирован, прежде чем им можно будет воспользоваться. (метод запроса)
Если 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 *ограничить мьютекс,
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);//перезагрузка

добавить.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 условие = 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 *ограничить мьютекс,
const struct timespec *restrict abstime);
int pthread_cond_wait(pthread_cond_t *restrict cond, // ограничение
pthread_mutex_t *ограничить мьютекс);

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, а семафор — тип 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. }

мойсем.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

основной.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

блокировка чтения-записи

Комплексное использование мьютексов и семафоров. Разделяется на блокировку чтения (семафор) и блокировку записи (мьютекс). Как правило, верхний предел должен быть установлен для чтения и записи.

Необходимо не дать писателям умереть с голоду.

4. Атрибуты, связанные с потоком

Второй параметр 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);
См. 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 *ограничить тип);
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int тип);

Свойства условной переменной:
int pthread_condattr_destroy(pthread_condattr_t *attr);
int pthread_condattr_init(pthread_condattr_t *attr);
Свойства блокировки чтения-записи:

5. Повторный вход

Реентерабельная функция — это просто функция, которую можно прервать. То есть вы можете прервать эту функцию в любой момент во время ее выполнения и перейти к планированию ОС для выполнения другого фрагмента кода без каких-либо ошибок при возврате управления; функции используют некоторые системные ресурсы, такие как области глобальных переменных, таблицы векторов прерываний и т. д., поэтому в случае их прерывания могут возникнуть проблемы. Такие функции не могут работать в многозадачной среде.

IO в многопоточности. Разблокированная функция заканчивается (нереентерабельная функция, многопоточный параллелизм не поддерживается). man putc_unlocked, просмотрите неподдерживаемые операции ввода-вывода.

Потоки и сигналы

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, int sig);

стандарт потока openmp

Посетите официальный сайт: www.OpenMp.org.

Теги синтаксиса Openmp поддерживаются после gcc4.0.Сколько параллелизма можно достичь с помощью всего лишь нескольких процессоров?

Привет

  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. }