线程
线程句柄
- typedef rt_thread_t pthread_t;
pthread_t是rt_thread_t类型的重定义,定义在pthread.h头文件里。rt_thread_t是RT-Thread的线程句柄(或线程标识符),是指向线程控制块的指针。在创建线程前需要先定义一个pthread_t类型的变量。每个线程都对应了自己的线程控制块,线程控制块是操作系统用于控制线程的一个数据结构,它存放了线程的一些信息,例如优先级,线程名称和线程堆栈地址等。线程控制块及线程具体信息在RT-Thread编程手册的线程调度与管理一章有详细的介绍。
创建线程
函数原型
- int pthread_create (pthread_t *tid,
- const pthread_attr_t *attr,
- void *(*start) (void *), void *arg);
- 参数 描述
- tid 指向线程句柄(线程标识符)的指针,不能为NULL
- attr 指向线程属性的指针,如果使用NULL,则使用默认的线程属性
- start 线程入口函数地址
- arg 传递给线程入口函数的参数
函数返回
创建成功返回0,参数无效返回EINVAL,如果因为动态分配内存失败则返回ENOMEM。
此函数创建一个pthread线程。此函数会动态分配POSIX线程数据块和RT-Thread线程控制块,并把线程控制块的起始地址(线程ID)保存在参数tid指向的内存里,此线程标识符可用于在其他线程中操作此线程;并把attr指向的线程属性、start指向的线程入口函数及入口函数参数arg保存在线程数据块和线程控制块里。如果线程创建成功,线程立刻进入就绪态,参与系统的调度,如果线程创建失败,则会释放之前线程占有的资源。
关于线程属性及相关函数会在线程高级编程一章里有详细介绍,一般情况下采用默认属性就可以。
注意:创建出pthread线程后,如果线程需要重复创建使用,需要设置pthread线程为detach模式,或者使用pthread_join等待创建后的pthread线程结束。
创建线程示例代码
以下程序会初始化2个线程,它们拥有共同的入口函数,但是它们的入口参数不相同。其他的,它们具备相同的优先级,并以时间片进行轮转调度。
- #include <pthread.h>
- #include <unistd.h>
- #include <stdio.h>
- /* 线程控制块 */
- static pthread_t tid1;
- static pthread_t tid2;
- /* 函数返回值检查 */
- static void check_result(char* str,int result)
- {
- if (0 == result)
- {
- printf("%s successfully!\n",str);
- }
- else
- {
- printf("%s failed! error code is %d\n",str,result);
- }
- }
- /* 线程入口函数*/
- static void* thread_entry(void* parameter)
- {
- int count = 0;
- int no = (int) parameter; /* 获得线程的入口参数 */
- while (1)
- {
- /* 打印输出线程计数值 */
- printf("thread%d count: %d\n", no, count ++);
- sleep(2); /* 休眠2秒 */
- }
- }
- /* 用户应用入口 */
- int rt_application_init()
- {
- int result;
- /* 创建线程1, 属性为默认值,入口函数是thread_entry,入口函数参数是1 */
- result = pthread_create(&tid1,NULL,thread_entry,(void*)1);
- check_result("thread1 created", result);
- /* 创建线程2, 属性为默认值,入口函数是thread_entry,入口函数参数是2 */
- result = pthread_create(&tid2,NULL,thread_entry,(void*)2);
- check_result("thread2 created", result);
- return 0;
- }
线程脱离
函数原型
- int pthread_detach (pthread_t thread);
- 参数 描述
- 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次信息后自动退出,退出后系统将会自动回收其资源。
- #include <pthread.h>
- #include <unistd.h>
- #include <stdio.h>
- /* 线程控制块 */
- static pthread_t tid1;
- static pthread_t tid2;
- /* 函数返回值检查 */
- static void check_result(char* str,int result)
- {
- if (0 == result)
- {
- printf("%s successfully!\n",str);
- }
- else
- {
- printf("%s failed! error code is %d\n",str,result);
- }
- }
- /* 线程1入口函数*/
- static void* thread1_entry(void* parameter)
- {
- int i;
- printf("i'm thread1 and i will detach myself!\n");
- pthread_detach(pthread_self()); /*线程1脱离自己*/
- for (i = 0;i < 3;i++) /* 循环打印3次信息 */
- {
- printf("thread1 run count: %d\n",i);
- sleep(2); /* 休眠2秒 */
- }
- printf("thread1 exited!\n");
- return NULL;
- }
- /* 线程2入口函数*/
- static void* thread2_entry(void* parameter)
- {
- int i;
- for (i = 0;i < 3;i++) /* 循环打印3次信息 */
- {
- printf("thread2 run count: %d\n",i);
- sleep(2); /* 休眠2秒 */
- }
- printf("thread2 exited!\n");
- return NULL;
- }
- /* 用户应用入口 */
- int rt_application_init()
- {
- int result;
- /* 创建线程1,属性为默认值,分离状态为默认值joinable,
- * 入口函数是thread1_entry,入口函数参数为NULL */
- result = pthread_create(&tid1,NULL,thread1_entry,NULL);
- check_result("thread1 created",result);
- /* 创建线程2,属性为默认值,分离状态为默认值joinable,
- * 入口函数是thread2_entry,入口函数参数为NULL */
- result = pthread_create(&tid2,NULL,thread2_entry,NULL);
- check_result("thread2 created",result);
- pthread_detach(tid2); /* 脱离线程2 */
- return 0;
- }
等待线程结束
函数原型
- int pthread_join (pthread_t thread, void **value_ptr);
- 参数 描述
- thread 线程句柄(线程标识符)
- 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秒钟会打印一次信息。
- #include <pthread.h>
- #include <unistd.h>
- #include <stdio.h>
- /* 线程控制块*/
- static pthread_t tid1;
- static pthread_t tid2;
- /* 函数返回值检查 */
- static void check_result(char* str,int result)
- {
- if (0 == result)
- {
- printf("%s successfully!\n",str);
- }
- else
- {
- printf("%s failed! error code is %d\n",str,result);
- }
- }
- /* 线程1入口函数 */
- static void* thread1_entry(void* parameter)
- {
- int i;
- for (int i = 0;i < 3;i++) /* 循环打印3次信息 */
- {
- printf("thread1 run count: %d\n",i);
- sleep(2); /* 休眠2秒 */
- }
- printf("thread1 exited!\n");
- return NULL;
- }
- /* 线程2入口函数*/
- static void* thread2_entry(void* parameter)
- {
- int count = 0;
- void* thread1_return_value;
- /* 阻塞等待线程1运行结束 */
- pthread_join(tid1, NULL);
- /* 线程2打印信息开始输出 */
- while(1)
- {
- /* 打印线程计数值输出 */
- printf("thread2 run count: %d\n",count ++);
- sleep(2); /* 休眠2秒 */
- }
- return NULL;
- }
- /* 用户应用入口 */
- int rt_application_init()
- {
- int result;
- /* 创建线程1,属性为默认值,分离状态为默认值joinable,
- * 入口函数是thread1_entry,入口函数参数为NULL */
- result = pthread_create(&tid1,NULL,thread1_entry,NULL);
- check_result("thread1 created",result);
- /* 创建线程2,属性为默认值,分离状态为默认值joinable,
- * 入口函数是thread2_entry,入口函数参数为NULL */
- result = pthread_create(&tid2,NULL,thread2_entry,NULL);
- check_result("thread2 created",result);
- return 0;
- }
线程退出
函数原型
- void pthread_exit(void *value_ptr);
- 参数 描述
- value_ptr 用户定义的指针,用来存储被等待线程的返回值地址,可由函数pthread_join()获取
函数返回
此函数没有返回值。
pthread线程调用此函数会终止执行,如同进程调用exit()函数一样,并返回一个指向线程返回值的指针。线程退出由线程自身发起。
注意:若线程的分离状态为joinable,线程退出后该线程占用的资源并不会被释放,必须调用pthread_join()函数释放线程占用的资源。
线程退出示例代码
这个程序会初始化2个线程,它们拥有相同的优先级,相同优先级的线程是按照时间片轮转调度。2个线程属性的分离状态为默认值joinable,线程1先开始运行,打印一次信息后休眠2秒,之后打印退出信息然后结束运行。线程2调用pthread_join()阻塞等待线程1结束,并回收线程1占用的资源,然后线程2每隔2秒钟会打印一次信息。
- #include <pthread.h>
- #include <unistd.h>
- #include <stdio.h>
- /* 线程控制块 */
- static pthread_t tid1;
- static pthread_t tid2;
- /* 函数返回值核对函数 */
- static void check_result(char* str,int result)
- {
- if (0 == result)
- {
- printf("%s successfully!\n",str);
- }
- else
- {
- printf("%s failed! error code is %d\n",str,result);
- }
- }
- /* 线程1入口函数*/
- static void* thread1_entry(void* parameter)
- {
- int count = 0;
- while(1)
- {
- /* 打印线程计数值输出 */
- printf("thread1 run count: %d\n",count ++);
- sleep(2); /* 休眠2秒 */
- printf("thread1 will exit!\n");
- pthread_exit(0); /* 线程1主动退出 */
- }
- }
- /* 线程2入口函数*/
- static void* thread2_entry(void* parameter)
- {
- int count = 0;
- /* 阻塞等待线程1运行结束 */
- pthread_join(tid1,NULL);
- /* 线程2开始输出打印信息 */
- while(1)
- {
- /* 打印线程计数值输出 */
- printf("thread2 run count: %d\n",count ++);
- sleep(2); /* 休眠2秒 */
- }
- }
- /* 用户应用入口 */
- int rt_application_init()
- {
- int result;
- /* 创建线程1,属性为默认值,分离状态为默认值joinable,
- * 入口函数是thread1_entry,入口函数参数为NULL */
- result = pthread_create(&tid1,NULL,thread1_entry,NULL);
- check_result("thread1 created",result);
- /* 创建线程2,属性为默认值,分离状态为默认值joinable,
- * 入口函数是thread2_entry,入口函数参数为NULL */
- result = pthread_create(&tid2,NULL,thread2_entry,NULL);
- check_result("thread2 created",result);
- return 0;
- }