Compartir tecnología

Lenguaje C: operaciones de concurrencia avanzadas (hilos)

2024-07-12

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

1. El concepto de hilo

Subproceso: una entidad en un proceso y la unidad básica de programación y envío de CPU. Básicamente, el subproceso en sí no posee recursos del sistema, solo algunos recursos que son esenciales para la ejecución (como un contador de programa, un conjunto de registros y una pila), pero puede compartir todos los recursos que posee el proceso con otros subprocesos. que pertenecen al mismo proceso. Un hilo puede crear y destruir otro hilo; varios hilos en el mismo proceso pueden ejecutarse simultáneamente. Los hilos muestran un comportamiento intermitente durante la operación. (Lo anterior es del "Tutorial de computadora de nivel 4: principios del sistema operativo")

Cuando se trata de subprocesos, es necesario hablar sobre la definición de proceso: un proceso es un programa con ciertas funciones independientes. Un proceso es una unidad independiente para la asignación y programación de recursos en el sistema. (Lo anterior es del "Tutorial de computadora de nivel 4: principios del sistema operativo")

La definición de proceso es un poco complicada. Veamos en qué consiste un proceso: programa, datos y bloque de control de proceso. Entre ellos, el programa corresponde a "un programa con ciertas funciones independientes" en la definición del proceso. Sin embargo, además del programa en sí, el proceso también necesita datos (que pueden entenderse como recursos) y bloques de control del proceso. Los bloques de control de procesos y datos son recursos esenciales cuando un programa se está ejecutando. El programa depende de estos recursos para realizar las actividades correspondientes, que es lo que llamamos un "proceso".

Dos propiedades básicas de los procesos:

Un proceso es una unidad independiente que puede poseer recursos;
Un proceso es una unidad básica que se puede programar y enviar de forma independiente.
Cuando se establecieron los subprocesos por primera vez, fue para separar los dos atributos anteriores del proceso. Los subprocesos constituyen la "unidad básica de programación y distribución de la CPU". De esta manera, puede haber muchos subprocesos en un proceso y el sistema operativo puede programarlos. y enviar subprocesos para mejorar Puede realizar la ejecución paralela de procesos al mismo tiempo, los subprocesos bajo el mismo proceso pueden compartir todos los recursos del proceso, lo que puede satisfacer el acceso a recursos del proceso por parte de diferentes subprocesos bajo el mismo proceso. La aparición de subprocesos separa inteligentemente los dos atributos del proceso, lo que permite que el proceso maneje mejor las necesidades de ejecución paralela.

Un hilo es una función en ejecución. Los subprocesos POSIX son un conjunto de estándares, no un conjunto de implementaciones. Existen otros estándares como: hilos openmp.
Identificador del hilo: pthread_t (no conozco el contenido específico, cada empresa lo implementa de manera diferente, en Linux es int)
El comando px axm ve procesos y subprocesos, que representan subprocesos bajo un proceso. px ax -L para ver hilos ligeros.

int pthread_equal(pthread_t t1, pthread_t t2); compara los números de identificación de dos subprocesos. Si son iguales, se devuelve un valor distinto de cero; si son diferentes, se devuelve 0.
pthread_t pthread_self(void); obtiene el ID del hilo actual

2. Creación de hilos

int pthread_create(pthread_t *hilo, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
La programación de subprocesos depende de la estrategia del programador.

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

Terminación de hilo

1. El hilo regresa de la rutina de inicio y el valor de retorno es el código de salida del hilo.
2. Los hilos pueden ser cancelados por otros hilos en el mismo proceso.
3. El hilo llama a la función pthread_exit(). void pthread_exit(void *retval);

int pthread_join(pthread_t thread, void **retval); Equivale a la espera del proceso y se utiliza para recolectar cadáveres.

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

limpieza de pila

pthread_cleanup_push(); //Equivalente a atexit
pthread_cleanup_pop(); //Equivalente a buscar datos activamente.

void pthread_cleanup_push(void (*routine)(void *), es la implementación de la macro, gcc -E para ver el preprocesamiento
vacío *arg);
void pthread_cleanup_pop(int ejecutar); //Elige si llamar.Deben aparecer en pares, implementados con macros.

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

Cancelar opciones para hilos

Si el hilo en ejecución quiere recolectar el cadáver, primero debe cancelar (pthread_cancel) y luego recolectar el cadáver (pthread_join).

Cancelación de hilo: int pthread_cancel(pthread_t hilo);
La cancelación tiene dos estados: permitida y no permitida.
Cancelación no permitida: la ejecución del código continúa sin verse afectada.
La cancelación permitida se divide en: cancelación asincrónica y cancelación retrasada (predeterminada) -&gt; respuesta retrasada hasta el punto de cancelación.
Punto de cancelación: los puntos de cancelación definidos por Posix son llamadas al sistema que pueden causar congestión.
pthread_setcancelstate: se puede establecer el estado de cancelación.
pthread_setcanceltype: puede configurar el método de cancelación.
pthread_testcancel: la función no hace nada, solo cancela el punto.

Separación de subprocesos: int pthread_detach(pthread_t thread);

Función de inicialización única del módulo dinámico: int pthread_once(pthread_once_t *once_control,
vacío (*init_routine)(vacío));
pthread_once_t control_una_vez = PTHREAD_ONCE_INIT;
 

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

Habrá competencia cuando se ejecute el código anterior. Debido a que los parámetros se pasan por dirección, los datos deben recuperarse mediante * y no hay garantía de que el hilo anterior haya realizado la operación. El método más simple es utilizar el paso de valores.

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

añadir.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. }

Pueden surgir competencias y conflictos cuando veinte subprocesos leen y escriben datos en un archivo al mismo tiempo. Antes de que un hilo escriba, otro hilo lee los últimos datos.

mitbf.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. Sincronización de hilos

exclusión mutua

Es equivalente a una cerradura y debe desbloquearse antes de poder operarse. (método de consulta)
Si man pthread_mutex_init informa un error, instale las dependencias:
sudo apt-get install páginas-manuales-posix páginas-manuales-posix-dev

int pthread_mutex_destroy(pthread_mutex_t *mutex); //Destruye el bloqueo
int pthread_mutex_init(pthread_mutex_t *restringir mutex,
const pthread_mutexattr_t *restringir inicialización dinámica);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER inicialización estática;

int pthread_mutex_lock(pthread_mutex_t *mutex); //Detener
int pthread_mutex_trylock(pthread_mutex_t *mutex);//Intenta bloquear, si no, continúa la ejecución
int pthread_mutex_unlock(pthread_mutex_t *mutex);//Detener

añadir.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
Utilice la cadena para bloquear y desbloquear.

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

El algoritmo de grupo implementa el cálculo de números primos (método de consulta)

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

variable de condición

Acta de notificación para la comunicación.

pthread_cond_destroy(cond_destroy *);
int pthread_cond_init(pthread_cond_t *restringir condición,
const pthread_condattr_t *restringir atributo);
pthread_cond_t cond = PTHREAD_COND_INICIALIZADOR;
int pthread_cond_broadcast(pthread_cond_t *cond); //Despierta a todos los que están esperando
int pthread_cond_signal(pthread_cond_t *cond);//Despierta cualquier espera
int pthread_cond_timedwait(pthread_cond_t *restringir cond, //tiempo de espera de espera
pthread_mutex_t *restringir mutex,
const struct timespec *restrict abstime);
int pthread_cond_wait(pthread_cond_t *restrict cond, //Restringir condición
pthread_mutex_t *restringir mutex);

mytbf.c (método de notificación)

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

señal

El mutex es de tipo bool y el semáforo es de tipo int. Se decrementa cuando se usa, si no es suficiente, espera.

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

misem.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 Principal

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

archivo make

  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

bloqueo de lectura-escritura

Uso integral de mutexes y semáforos. Dividido en bloqueo de lectura (semáforo) y bloqueo de escritura (mutex). Generalmente, se debe establecer un límite superior para lectura y escritura.

Es necesario evitar que los escritores mueran de hambre.

4. Atributos relacionados con los hilos

El segundo parámetro de pthread_create es el atributo del hilo.

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

El número máximo de subprocesos creados por el programa de prueba. ()

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

Propiedades de sincronización de subprocesos

Propiedades mutuas:

pthread_mutexattr_init(pthread_mutexattr_t *attr);
Consulte pthread_mutexattr_destroy().
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, //funciona en todos los procesos
int *pshared);
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr,
int compartido);

//Cree un proceso hijo que pueda compartir la matriz de descriptores de archivos. También puede optar por no compartirlo. No hay distinción entre procesos y subprocesos en Linux
int clone(int (*fn)(void *), void *stack, int banderas, void *arg, ...
/* pid_t *tid_padre, void *tls, pid_t *tid_hijo */ );
int pthread_mutexattr_gettype(const pthread_mutexattr_t *atr de restricción,
int *restringir tipo);
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int tipo);

Propiedades de las variables de condición:
pthread_condattr_destroy(pthread_condattr_t *attr);
pthread_condattr_t *attr es un atributo de la instrucción pthread_condattr_t.
Propiedades de bloqueo de lectura y escritura:

5. Reingreso

Una función reentrante es simplemente una función que se puede interrumpir, es decir, puede interrumpir esta función en cualquier momento durante su ejecución y transferirla a la programación del sistema operativo para ejecutar otro fragmento de código sin ningún error al devolver el control. Las funciones utilizan algunos recursos del sistema, como áreas de variables globales, tablas de vectores de interrupción, etc., por lo que si se interrumpen, pueden ocurrir problemas. Dichas funciones no se pueden ejecutar en un entorno multitarea.

IO en subprocesos múltiples. La función desbloqueada termina en (función no reentrante, no se admite la concurrencia de subprocesos múltiples). man putc_unlocked, ver operaciones IO no admitidas.

Hilos y señales

int pthread_sigmask(int cómo, const sigset_t *conjunto, sigset_t *conjuntoantiguo);
int sigwait(const sigset_t *conjunto, int *sig);
int pthread_kill(pthread_t hilo, int sig);

estándar de hilo openmp

Consulte el sitio web oficial: www.OpenMp.org

Las etiquetas de sintaxis Openmp son compatibles después de gcc4.0.¿Cuántas concurrencias se pueden lograr con solo unas pocas CPU?

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

archivo make

CFLAGS += -Wall -fopenmp

Compile make hola y ejecútelo.

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