当前位置:   article > 正文

嵌入式学习第二十二天!(线程间通信)

嵌入式学习第二十二天!(线程间通信)

线程间通信:

        线程间通信,通过利用全局变量,来实现通信,但是在通信过程中使用这些变量可能会导致资源竞争,那么就需要使用到互斥锁信息量,辅助我们实现线程的通信。

1. 线程分离属性:

    线程结束后,自动回收线程空间

    1. pthread_attr_init:

int pthread_attr_init(pthread_attr_t *attr);

        功能:线程属性初始化

    2. pthread_attr_destroy:

int pthread_attr_destroy(pthread_attr_t *attr);

        功能:线程属性销毁

    3. pthread_attr_setdetachstate:

int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);

        功能:设置分离属性

            PTHREAD_CREATE_DETACHED   分离属性
            PTHREAD_CREATE_JOINABLE   加入属性(默认)

    练习:

       1. 利用线程的分离属性创建三个线程,打印线程id

  1. #include "head.h"
  2. void *thread1(void *arg)
  3. {
  4. printf("stat to thread1(tid:%#x)\n", (unsigned int)pthread_self());
  5. return NULL;
  6. }
  7. void *thread2(void *arg)
  8. {
  9. printf("stat to thread2(tid:%#x)\n", (unsigned int)pthread_self());
  10. return NULL;
  11. }
  12. void *thread3(void *arg)
  13. {
  14. printf("stat to thread2(tid:%#x)\n", (unsigned int)pthread_self());
  15. return NULL;
  16. }
  17. int main(void)
  18. {
  19. int i = 0;
  20. pthread_t thread[3];
  21. void *(*p[3])(void *) = {thread1, thread2, thread3};
  22. pthread_attr_t attr;
  23. pthread_attr_init(&attr);
  24. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  25. for(i = 0; i < 3; i++)
  26. {
  27. pthread_create(&thread[i], &attr, p[i], NULL);
  28. }
  29. pthread_attr_destroy(&attr);
  30. while(1)
  31. {
  32. }
  33. }

        2. 首先定义一个学生结构体,包含姓名、性别、年龄、分数。再创建两个两个线程,线程1负责从终端接收学生信息,线程2负责将学生信息打印在终端。

  1. #include "head.h"
  2. struct studet
  3. {
  4. char name[100];
  5. char sex;
  6. int age;
  7. int score;
  8. };
  9. void *InputInfo(void *arg)
  10. {
  11. struct studet *stu = arg;
  12. char *ptmp = stu->name;
  13. fgets(stu->name, 100, stdin);
  14. ptmp[strlen(ptmp)-1] = '\0';
  15. scanf("%c", &stu->sex);
  16. scanf("%d", &stu->age);
  17. scanf("%d", &stu->score);
  18. return NULL;
  19. }
  20. void *OutputInfo(void *arg)
  21. {
  22. struct studet *stu = arg;
  23. sleep(5);
  24. printf("%s\n", stu->name);
  25. printf("%c\n", stu->sex);
  26. printf("%d\n", stu->age);
  27. printf("%d\n", stu->score);
  28. return NULL;
  29. }
  30. int main(void)
  31. {
  32. struct studet t;
  33. pthread_t input;
  34. pthread_t output;
  35. pthread_create(&input, NULL, InputInfo, &t);
  36. pthread_create(&output, NULL, OutputInfo, &t);
  37. pthread_join(input, NULL);
  38. pthread_join(output, NULL);
  39. return 0;
  40. }

2. 线程互斥:

    1. 互斥锁:

        防止资源竞争

    2. 函数接口:

        1. pthread_mutex_init:
  1. int pthread_mutex_init(pthread_mutex_t *restrict mutex,
  2. const pthread_mutexattr_t *restrict attr);

            功能:互斥锁初始化

            参数:

                mutex:互斥锁空间首地址
                attr:互斥锁的属性(默认为NULL)

            返回值:

                成功返回0 
                失败返回错误码

        2. pthread_mutex_destroy:
int pthread_mutex_destroy(pthread_mutex_t *mutex);

            功能:互斥锁销毁

            参数:

                mutex:互斥锁空间首地址

            返回值:

                成功返回0 
                失败返回错误码

        3. pthread_mutex_lock:
int pthread_mutex_lock(pthread_mutex_t *mutex);

            功能:上锁

        4. pthread_mutex_unlock:
int pthread_mutex_unlock(pthread_mutex_t *mutex);

            功能:解锁

    3. 临界资源、临界区:

        加锁解锁中间的代码称为临界资源、临界区

        同一时刻临界资源不能同时执行,只能执行其中一个临界资源代码

    4. 原子操作:

        CPU最小的一次不能被任务调度打断的操作称为原子操作

    5. 注意:

        互斥锁只能解决资源竞争的问题,无法同步代码(没有先后执行的顺序关系)

    练习:

        定义三个整型的全局变量Num1, Num2,val,创建两个线程,一个线程循环令Num1=val,Num2=val,val自加;另一个线程,循环判断:当Num1不等于Num2的时候,输出Num1和Num2的值。利用互斥锁,让Num1始终等于Num2,使终端没有输出。

  1. #include "head.h"
  2. int val = 0;
  3. int Num1 = 0;
  4. int Num2 = 0;
  5. pthread_mutex_t lock;
  6. void *thread1(void *arg)
  7. {
  8. while(1)
  9. {
  10. pthread_mutex_lock(&lock);
  11. Num1 = val;
  12. Num2 = val;
  13. pthread_mutex_unlock(&lock);
  14. val++;
  15. }
  16. return NULL;
  17. }
  18. void *thread2(void *arg)
  19. {
  20. while(1)
  21. {
  22. pthread_mutex_lock(&lock);
  23. if(Num1 != Num2)
  24. {
  25. printf("Num1 = %d, Num2 = %d\n", Num1, Num2);
  26. }
  27. pthread_mutex_unlock(&lock);
  28. }
  29. return NULL;
  30. }
  31. int main(void)
  32. {
  33. pthread_t tid1;
  34. pthread_t tid2;
  35. pthread_mutex_init(&lock, NULL);
  36. pthread_create(&tid1, NULL, thread1, NULL);
  37. pthread_create(&tid2, NULL, thread2, NULL);
  38. pthread_join(tid1, NULL);
  39. pthread_join(tid2, NULL);
  40. pthread_mutex_destroy(&lock);
  41. return 0;
  42. }

3. 死锁:

    多线程操作互斥锁,导致多个线程均违法向下执行的状态称为死锁状态,简称为死锁

    1. 死锁产生的四个必要条件:

        1. 互斥条件

        2. 不可剥夺条件

        3. 请求保持

        4. 循环等待

    2. 如何避免产生死锁:

        1. pthread_mutex_trylock 替代 pthread_mutex_lock

        2. 加锁顺序保持一致

4. 信号量:

    信号量是一种资源,可以被初始化、申请、释放、销毁

    P操作:申请资源

    V操作:释放资源

    1. sem_init:

int sem_init(sem_t *sem, int pshared, unsigned int value);

        功能:初始化信号量

        参数:

            sem:信号量空间首地址

            pshared:为0的话,是一个进程中的所有线程间共享;非0的话,则是进程间共享

            value:初始化的值

        返回值:

           成功返回0 
           失败返回-1 

    2. sem_destory:

int sem_destroy(sem_t *sem);

        功能:信号量的销毁

        参数:

            sem:信号量空间首地址

        返回值:

            成功返回0 
            失败返回-1

    3. sem_wait:

int sem_wait(sem_t *sem);

        功能:申请信号量

    4. sem_post:

int sem_post(sem_t *sem);

        功能:释放信号量

作业:

        1. 创建三个线程分别循环打印 A B C,要求打印出来的顺序总是 A -> B -> C

  1. #include "head.h"
  2. sem_t sem_a;
  3. sem_t sem_b;
  4. sem_t sem_c;
  5. void *thread1(void* arg)
  6. {
  7. while(1)
  8. {
  9. sem_wait(&sem_a);
  10. printf("A\n");
  11. sem_post(&sem_b);
  12. }
  13. return NULL;
  14. }
  15. void *thread2(void* arg)
  16. {
  17. while(1)
  18. {
  19. sem_wait(&sem_b);
  20. printf("B\n");
  21. sem_post(&sem_c);
  22. }
  23. return NULL;
  24. }
  25. void *thread3(void* arg)
  26. {
  27. while(1)
  28. {
  29. sem_wait(&sem_c);
  30. printf("C\n");
  31. sem_post(&sem_a);
  32. }
  33. return NULL;
  34. }
  35. int main(void)
  36. {
  37. int i = 0;
  38. pthread_t tid[3];
  39. void *(*p[3])(void *) = {thread1, thread2, thread3};
  40. sem_init(&sem_a, 0, 1);
  41. sem_init(&sem_b, 0, 0);
  42. sem_init(&sem_c, 0, 0);
  43. for(i = 0; i < 3; i++)
  44. {
  45. pthread_create(&tid[i], NULL, p[i], NULL);
  46. }
  47. for(i = 0; i < 3; i++)
  48. {
  49. pthread_join(tid[i], NULL);
  50. }
  51. sem_destroy(&sem_a);
  52. sem_destroy(&sem_b);
  53. sem_destroy(&sem_c);
  54. return 0;
  55. }

        2. PTA | 程序设计类实验辅助教学平台

  1. #include <stdio.h>
  2. struct student
  3. {
  4. char number[20];
  5. int testbit;
  6. int exambit;
  7. };
  8. int GetStudentBit(struct student *pstu, int maxlen)
  9. {
  10. int n = 0;
  11. int i = 0;
  12. scanf("%d", &n);
  13. if(n > maxlen)
  14. {
  15. perror("Over to limit");
  16. return -1;
  17. }
  18. for(i = 0; i < n; i++)
  19. {
  20. scanf("%s %d %d", pstu[i].number, &pstu[i].testbit, &pstu[i].exambit);
  21. }
  22. return n;
  23. }
  24. int GetFoundBit(int *pbit, int maxlen)
  25. {
  26. int m = 0;
  27. int i = 0;
  28. scanf("%d", &m);
  29. if(m > maxlen)
  30. {
  31. perror("Over to limit");
  32. return -1;
  33. }
  34. for(i = 0; i < m; i++)
  35. {
  36. scanf("%d", &pbit[i]);
  37. }
  38. return m;
  39. }
  40. int PrintStudentBit(struct student *pstu, int curlen, int *pfound, int m)
  41. {
  42. int i = 0;
  43. int j = 0;
  44. for(i = 0; i < m; i++)
  45. {
  46. for(j = 0; j < curlen; j++)
  47. {
  48. if(pstu[j].testbit == pfound[i])
  49. {
  50. printf("%s %d\n", pstu[j].number, pstu[j].exambit);
  51. }
  52. }
  53. }
  54. return 0;
  55. }
  56. int main(void)
  57. {
  58. struct student stu[1000];
  59. int curlen = 0;
  60. int bitinfo[1000];
  61. int foundnum = 0;
  62. curlen = GetStudentBit(stu, 1000);
  63. foundnum = GetFoundBit(bitinfo, 1000);
  64. PrintStudentBit(stu, curlen, bitinfo, foundnum);
  65. return 0;
  66. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/169821
推荐阅读
相关标签
  

闽ICP备14008679号