기술나눔

C 언어: 고급 동시성 작업(스레드)

2024-07-12

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

1. 스레드의 개념

스레드(Thread): 프로세스의 엔터티이자 CPU 스케줄링 및 디스패치의 기본 단위입니다. 스레드 자체는 기본적으로 시스템 리소스를 소유하지 않으며 실행에 필수적인 몇 가지 리소스(예: 프로그램 카운터, 레지스터 집합, 스택)만 소유하지만 프로세스가 소유한 모든 리소스를 다른 스레드와 공유할 수 있습니다. 이는 동일한 프로세스에 속합니다. 스레드는 다른 스레드를 만들고 삭제할 수 있습니다. 동일한 프로세스의 여러 스레드가 동시에 실행될 수 있습니다. 스레드는 작업 중에 간헐적으로 동작합니다. (위 내용은 "컴퓨터 레벨 4 튜토리얼 - 운영 체제 원리"에서 발췌한 것입니다.)

스레드에 관해서는 프로세스의 정의에 대해 이야기할 필요가 있습니다. 프로세스는 특정 독립적인 기능을 가진 프로그램입니다. 프로세스는 시스템에서 자원 할당 및 스케줄링을 위한 독립적인 단위입니다. (위 내용은 "컴퓨터 레벨 4 튜토리얼 - 운영 체제 원리"에서 발췌한 것입니다.)

프로세스의 정의는 다소 복잡합니다. 프로세스가 프로그램, 데이터 및 프로세스 제어 블록으로 구성되어 있는 것을 살펴보겠습니다. 그 중 프로그램은 프로세스 정의에서 "어떤 독립적인 기능을 가진 프로그램"에 해당합니다. 그러나 프로세스에는 프로그램 자체 외에도 데이터(리소스로 이해될 수 있음)와 프로세스 제어 블록도 필요합니다. 데이터 및 프로세스 제어 블록은 프로그램이 실행될 때 필수적인 리소스입니다. 프로그램은 이러한 리소스를 사용하여 "프로세스"라고 부르는 해당 활동을 수행합니다.

프로세스의 두 가지 기본 속성:

프로세스는 리소스를 소유할 수 있는 독립적인 단위입니다.
프로세스는 독립적으로 예약되고 발송될 수 있는 기본 단위입니다.
스레드가 처음 확립되었을 때는 프로세스의 위 두 가지 속성을 분리하기 위한 것이었습니다. 스레드는 "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를 가져옵니다.

2. 스레드 생성

int pthread_create(pthread_t *스레드, const pthread_attr_t *속성,
void *(*시작_루틴) (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); 프로세스의 대기와 동일하며 시체를 수집하는 데 사용됩니다.

  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 pthread_cleanup_pop(intexecute); //호출 여부를 선택합니다.쌍으로 나타나야 하며 매크로로 구현됨

클린업.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. }

위의 코드가 실행되면 경쟁이 발생합니다. 매개변수는 주소로 전달되기 때문에 *로 데이터를 검색해야 하며, 이전 스레드가 작업을 수행했는지 여부가 보장되지 않습니다. 가장 간단한 방법은 값 전달을 사용하는 것입니다.

프라이머0.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. }

프라이머0_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. }

20개의 스레드가 동시에 파일에서 데이터를 읽고 쓸 때 경쟁과 충돌이 발생할 수 있습니다. 한 스레드가 쓰기 전에 다른 스레드가 마지막 데이터를 읽습니다.

마이티비에프씨
  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 *조건);
int pthread_cond_init(pthread_cond_t *제한 조건,
const pthread_condattr_t *제한 속성);
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 구조체 시간 지정 *제한 절대시간);
int pthread_cond_wait(pthread_cond_t *제한 조건, //실수 등
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. }

프라이머0_풀.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_조건.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 유형입니다. 충분하지 않으면 대기합니다.

마이셈.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. }

메이크파일

  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 *속성);
int pthread_attr_destroy(pthread_attr_t *속성);

테스트 프로그램에서 생성된 최대 스레드 수입니다. ()

  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_mutex 속성_init(pthread_mutex 속성_t * 속성);
pthread_mutexattr_destroy()를 참조하세요.
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, //프로세스 간에 작동
int *p공유);
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr,
int pshared);

//파일 설명자 배열을 공유할 수 있는 하위 프로세스를 생성합니다. 공유하지 않도록 선택할 수도 있습니다. Linux에서는 프로세스와 스레드 사이에 구분이 없습니다.
int clone(int (*fn)(void *), void *stack, int 플래그, void *arg, ...
/* pid_t *부모_tid, void *tls, pid_t *자식_tid */);
int pthread_mutexattr_gettype(const pthread_mutexattr_t *제한 속성,
int *제한 유형);
int pthread_mutexattr_settype(pthread_mutexattr_t *속성, int 유형);

조건 변수 속성:
int pthread_condattr_destroy(pthread_condattr_t * 속성);
int pthread_condattr_init(pthread_condattr_t *속성);
읽기-쓰기 잠금 속성:

5. 재입장

재진입 기능은 단순히 중단될 수 있는 기능입니다. 즉, 실행 중에 언제든지 이 기능을 중단하고 제어를 반환할 때 오류 없이 다른 코드를 실행하도록 OS 스케줄링으로 전송할 수 있습니다. 함수는 전역 변수 영역, 인터럽트 벡터 테이블 등과 같은 일부 시스템 리소스를 사용하므로 중단되면 이러한 함수는 멀티 태스킹 환경에서 실행되지 않을 수 있습니다.

멀티스레딩의 IO. 잠금 해제된 기능은 (비재진입 기능, 다중 스레드 동시성은 지원되지 않음)로 끝납니다. 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 스레드, int sig);

openmp 스레드 표준

공식 웹사이트를 참조하세요: www.OpenMp.org

Openmp 구문 태그는 gcc4.0 이후에 지원됩니다.단 몇 개의 CPU로 얼마나 많은 동시성을 달성할 수 있습니까?

안녕하세요.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. }

메이크파일

CFLAGS += -Wall -fopenmp

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