线程

线程句柄

  1. typedef rt_thread_t pthread_t;

pthread_t是rt_thread_t类型的重定义,定义在pthread.h头文件里。rt_thread_t是RT-Thread的线程句柄(或线程标识符),是指向线程控制块的指针。在创建线程前需要先定义一个pthread_t类型的变量。每个线程都对应了自己的线程控制块,线程控制块是操作系统用于控制线程的一个数据结构,它存放了线程的一些信息,例如优先级,线程名称和线程堆栈地址等。线程控制块及线程具体信息在RT-Thread编程手册的线程调度与管理一章有详细的介绍。

创建线程

函数原型

  1. int pthread_create (pthread_t *tid,
  2. const pthread_attr_t *attr,
  3. void *(*start) (void *), void *arg);

  1. 参数 描述

  1. tid 指向线程句柄(线程标识符)的指针,不能为NULL
  2.  
  3. attr 指向线程属性的指针,如果使用NULL,则使用默认的线程属性
  4.  
  5. start 线程入口函数地址
  6.  
  7. arg 传递给线程入口函数的参数

函数返回

创建成功返回0,参数无效返回EINVAL,如果因为动态分配内存失败则返回ENOMEM。

此函数创建一个pthread线程。此函数会动态分配POSIX线程数据块和RT-Thread线程控制块,并把线程控制块的起始地址(线程ID)保存在参数tid指向的内存里,此线程标识符可用于在其他线程中操作此线程;并把attr指向的线程属性、start指向的线程入口函数及入口函数参数arg保存在线程数据块和线程控制块里。如果线程创建成功,线程立刻进入就绪态,参与系统的调度,如果线程创建失败,则会释放之前线程占有的资源。

关于线程属性及相关函数会在线程高级编程一章里有详细介绍,一般情况下采用默认属性就可以。

注意:创建出pthread线程后,如果线程需要重复创建使用,需要设置pthread线程为detach模式,或者使用pthread_join等待创建后的pthread线程结束。

创建线程示例代码

以下程序会初始化2个线程,它们拥有共同的入口函数,但是它们的入口参数不相同。其他的,它们具备相同的优先级,并以时间片进行轮转调度。

  1. #include <pthread.h>
  2. #include <unistd.h>
  3. #include <stdio.h>
  4.  
  5. /* 线程控制块 */
  6. static pthread_t tid1;
  7. static pthread_t tid2;
  8.  
  9. /* 函数返回值检查 */
  10. static void check_result(char* str,int result)
  11. {
  12. if (0 == result)
  13. {
  14. printf("%s successfully!\n",str);
  15. }
  16. else
  17. {
  18. printf("%s failed! error code is %d\n",str,result);
  19. }
  20. }
  21.  
  22. /* 线程入口函数*/
  23. static void* thread_entry(void* parameter)
  24. {
  25. int count = 0;
  26. int no = (int) parameter; /* 获得线程的入口参数 */
  27.  
  28. while (1)
  29. {
  30. /* 打印输出线程计数值 */
  31. printf("thread%d count: %d\n", no, count ++);
  32.  
  33. sleep(2); /* 休眠2秒 */
  34. }
  35. }
  36.  
  37. /* 用户应用入口 */
  38. int rt_application_init()
  39. {
  40. int result;
  41.  
  42. /* 创建线程1, 属性为默认值,入口函数是thread_entry,入口函数参数是1 */
  43. result = pthread_create(&tid1,NULL,thread_entry,(void*)1);
  44. check_result("thread1 created", result);
  45.  
  46. /* 创建线程2, 属性为默认值,入口函数是thread_entry,入口函数参数是2 */
  47. result = pthread_create(&tid2,NULL,thread_entry,(void*)2);
  48. check_result("thread2 created", result);
  49.  
  50. return 0;
  51. }

线程脱离

函数原型

  1. int pthread_detach (pthread_t thread);

  1. 参数 描述

  1. thread 线程句柄(线程标识符)

函数返回

只返回0,总是成功。

调用此函数,如果pthread线程没有结束,则将thread线程属性的分离状态设置为detached;当thread线程已经结束时,系统将回收pthread线程占用的资源。

使用方法:子线程调用pthread_detach(pthread_self())(pthread_self()返回当前调用线程的线程句柄),或者其他线程调用pthread_detach(thread_id)。关于线程属性的分离状态会在后面详细介绍。

注意:一旦线程属性的分离状态设置为detached,该线程不能被pthread_join()函数等待或者重新被设置为detached。

线程脱离示例代码

以下程序会初始化2个线程,它们拥有相同的优先级,并按照时间片轮转调度。2个线程都会被设置为脱离状态,2个线程循环打印3次信息后自动退出,退出后系统将会自动回收其资源。

  1. #include <pthread.h>
  2. #include <unistd.h>
  3. #include <stdio.h>
  4.  
  5. /* 线程控制块 */
  6. static pthread_t tid1;
  7. static pthread_t tid2;
  8.  
  9. /* 函数返回值检查 */
  10. static void check_result(char* str,int result)
  11. {
  12. if (0 == result)
  13. {
  14. printf("%s successfully!\n",str);
  15. }
  16. else
  17. {
  18. printf("%s failed! error code is %d\n",str,result);
  19. }
  20. }
  21.  
  22. /* 线程1入口函数*/
  23. static void* thread1_entry(void* parameter)
  24. {
  25. int i;
  26.  
  27. printf("i'm thread1 and i will detach myself!\n");
  28. pthread_detach(pthread_self()); /*线程1脱离自己*/
  29.  
  30. for (i = 0;i < 3;i++) /* 循环打印3次信息 */
  31. {
  32. printf("thread1 run count: %d\n",i);
  33. sleep(2); /* 休眠2秒 */
  34. }
  35.  
  36. printf("thread1 exited!\n");
  37. return NULL;
  38. }
  39.  
  40. /* 线程2入口函数*/
  41. static void* thread2_entry(void* parameter)
  42. {
  43. int i;
  44.  
  45. for (i = 0;i < 3;i++) /* 循环打印3次信息 */
  46. {
  47. printf("thread2 run count: %d\n",i);
  48. sleep(2); /* 休眠2秒 */
  49. }
  50.  
  51. printf("thread2 exited!\n");
  52. return NULL;
  53. }
  54. /* 用户应用入口 */
  55. int rt_application_init()
  56. {
  57. int result;
  58.  
  59. /* 创建线程1,属性为默认值,分离状态为默认值joinable,
  60. * 入口函数是thread1_entry,入口函数参数为NULL */
  61. result = pthread_create(&tid1,NULL,thread1_entry,NULL);
  62. check_result("thread1 created",result);
  63.  
  64. /* 创建线程2,属性为默认值,分离状态为默认值joinable,
  65. * 入口函数是thread2_entry,入口函数参数为NULL */
  66. result = pthread_create(&tid2,NULL,thread2_entry,NULL);
  67. check_result("thread2 created",result);
  68.  
  69. pthread_detach(tid2); /* 脱离线程2 */
  70.  
  71. return 0;
  72. }

等待线程结束

函数原型

  1. int pthread_join (pthread_t thread, void **value_ptr);

  1. 参数 描述

  1. thread 线程句柄(线程标识符)
  2.  
  3. value_ptr 用户定义的指针,用来存储被等待线程的返回值地址,可由函数pthread_join()获取

函数返回

执行成功返回0,线程join自己返回EDEADLK;join一个分离状态为detached的线程返回EINVAL;找不到pthread线程返回ESRCH。

此函数会使调用该函数的线程以阻塞的方式等待线程分离属性为joinable的thread线程运行结束,并获得thread线程的返回值,返回值的地址保存在value_ptr里,并释放thread线程占用的资源。

pthread_join()和pthread_detach()函数功能类似,都是在线程结束后用来回收线程占用的资源。线程不能等待自己结束,thread线程的分离状态必须是joinable,一个线程只对应一次pthread_join()调用。分离状态为joinable的线程仅当有其他线程对其执行了pthread_join()后,它所占用的资源才会释放。因此为了避免内存泄漏,所有会结束运行的线程,分离状态要么已设为detached,要么使用pthread_join()来回收其占用的资源。

等待线程结束示例代码

以下程序代码会初始化2个线程,它们拥有相同的优先级,相同优先级的线程是按照时间片轮转调度。2个线程属性的分离状态为默认值joinable,线程1先开始运行,循环打印3次信息后结束。线程2调用pthread_join()阻塞等待线程1结束,并回收线程1占用的资源,然后线程2每隔2秒钟会打印一次信息。

  1. #include <pthread.h>
  2. #include <unistd.h>
  3. #include <stdio.h>
  4.  
  5. /* 线程控制块*/
  6. static pthread_t tid1;
  7. static pthread_t tid2;
  8.  
  9. /* 函数返回值检查 */
  10. static void check_result(char* str,int result)
  11. {
  12. if (0 == result)
  13. {
  14. printf("%s successfully!\n",str);
  15. }
  16. else
  17. {
  18. printf("%s failed! error code is %d\n",str,result);
  19. }
  20. }
  21.  
  22. /* 线程1入口函数 */
  23. static void* thread1_entry(void* parameter)
  24. {
  25. int i;
  26.  
  27. for (int i = 0;i < 3;i++) /* 循环打印3次信息 */
  28. {
  29. printf("thread1 run count: %d\n",i);
  30. sleep(2); /* 休眠2秒 */
  31. }
  32.  
  33. printf("thread1 exited!\n");
  34. return NULL;
  35. }
  36.  
  37. /* 线程2入口函数*/
  38. static void* thread2_entry(void* parameter)
  39. {
  40. int count = 0;
  41. void* thread1_return_value;
  42.  
  43. /* 阻塞等待线程1运行结束 */
  44. pthread_join(tid1, NULL);
  45.  
  46. /* 线程2打印信息开始输出 */
  47. while(1)
  48. {
  49. /* 打印线程计数值输出 */
  50. printf("thread2 run count: %d\n",count ++);
  51. sleep(2); /* 休眠2秒 */
  52. }
  53.  
  54. return NULL;
  55. }
  56.  
  57. /* 用户应用入口 */
  58. int rt_application_init()
  59. {
  60. int result;
  61. /* 创建线程1,属性为默认值,分离状态为默认值joinable,
  62. * 入口函数是thread1_entry,入口函数参数为NULL */
  63. result = pthread_create(&tid1,NULL,thread1_entry,NULL);
  64. check_result("thread1 created",result);
  65.  
  66. /* 创建线程2,属性为默认值,分离状态为默认值joinable,
  67. * 入口函数是thread2_entry,入口函数参数为NULL */
  68. result = pthread_create(&tid2,NULL,thread2_entry,NULL);
  69. check_result("thread2 created",result);
  70.  
  71. return 0;
  72. }

线程退出

函数原型

  1. void pthread_exit(void *value_ptr);

  1. 参数 描述

  1. value_ptr 用户定义的指针,用来存储被等待线程的返回值地址,可由函数pthread_join()获取

函数返回

此函数没有返回值。

pthread线程调用此函数会终止执行,如同进程调用exit()函数一样,并返回一个指向线程返回值的指针。线程退出由线程自身发起。

注意:若线程的分离状态为joinable,线程退出后该线程占用的资源并不会被释放,必须调用pthread_join()函数释放线程占用的资源。

线程退出示例代码

这个程序会初始化2个线程,它们拥有相同的优先级,相同优先级的线程是按照时间片轮转调度。2个线程属性的分离状态为默认值joinable,线程1先开始运行,打印一次信息后休眠2秒,之后打印退出信息然后结束运行。线程2调用pthread_join()阻塞等待线程1结束,并回收线程1占用的资源,然后线程2每隔2秒钟会打印一次信息。

  1. #include <pthread.h>
  2. #include <unistd.h>
  3. #include <stdio.h>
  4.  
  5. /* 线程控制块 */
  6. static pthread_t tid1;
  7. static pthread_t tid2;
  8.  
  9. /* 函数返回值核对函数 */
  10. static void check_result(char* str,int result)
  11. {
  12. if (0 == result)
  13. {
  14. printf("%s successfully!\n",str);
  15. }
  16. else
  17. {
  18. printf("%s failed! error code is %d\n",str,result);
  19. }
  20. }
  21.  
  22. /* 线程1入口函数*/
  23. static void* thread1_entry(void* parameter)
  24. {
  25. int count = 0;
  26. while(1)
  27. {
  28. /* 打印线程计数值输出 */
  29. printf("thread1 run count: %d\n",count ++);
  30. sleep(2); /* 休眠2秒 */
  31. printf("thread1 will exit!\n");
  32.  
  33. pthread_exit(0); /* 线程1主动退出 */
  34. }
  35. }
  36.  
  37. /* 线程2入口函数*/
  38. static void* thread2_entry(void* parameter)
  39. {
  40. int count = 0;
  41.  
  42. /* 阻塞等待线程1运行结束 */
  43. pthread_join(tid1,NULL);
  44. /* 线程2开始输出打印信息 */
  45. while(1)
  46. {
  47. /* 打印线程计数值输出 */
  48. printf("thread2 run count: %d\n",count ++);
  49. sleep(2); /* 休眠2秒 */
  50. }
  51. }
  52.  
  53. /* 用户应用入口 */
  54. int rt_application_init()
  55. {
  56. int result;
  57.  
  58. /* 创建线程1,属性为默认值,分离状态为默认值joinable,
  59. * 入口函数是thread1_entry,入口函数参数为NULL */
  60. result = pthread_create(&tid1,NULL,thread1_entry,NULL);
  61. check_result("thread1 created",result);
  62.  
  63. /* 创建线程2,属性为默认值,分离状态为默认值joinable,
  64. * 入口函数是thread2_entry,入口函数参数为NULL */
  65. result = pthread_create(&tid2,NULL,thread2_entry,NULL);
  66. check_result("thread2 created",result);
  67.  
  68. return 0;
  69. }