POSIX:可移植操作系统接口(Portable Operating System Interface of UNIX,缩写为 POSIX ),是IEEE(电气与电子工程师协会)协会发布的一种操作系统通用化函数接口,用来在应用层实现开发的统一。主要是为了解决早年类Unix系统很多版本之间函数接口不能统一导致的很多开发上的不便。
经过多年的发展,在Uinx/Liunx系统发展过程中,posix系统进一步趋于完善,发展至今,尤其是在linux上,作为应用开发的通用API,具备了较高的可移植性和兼容性,几乎成为了现代操作系统应用开发API的标配。所以,与其说 POSIX 是一个东西,不如说是一个标签。想象一下,有一个盒子,上面贴着标签:POSIX,而盒子里是一个标准。
RT-Smart操作系统具备RT自身的一套完善的API,在应用开发过程中,尤其是之前按熟悉RT-Thread系统开发工程师们,在切换成Smart之后不会有任何的突兀和不适,RT自家的两个系统之间接口是高度统一的。但是对于选择使用Smart系统的工程师来说,最大的动力就是Smart的混合微内核的高效特性,可以用来替代庞大的linux,这种情况下,在linux上之前开发的应用程序,移植到Smart上的时候,只要接口是POSIX标准,那么理论上就可以在用户态直接编译运行elf文件,而不必再用RT的接口标准对程序进行重写。这将大大减少程序移植的复杂度。因此从本篇开始,将会针对POSIX接口进行几个常用模块的程序编写与运行工作,来测试一下Smart对POSIX接口的应用程序支持情况。
POSIX标准下对线程的操作常用的基本API接口包括下面几个:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);
函数参数:
返回值:
int pthread_join( pthread_t thread, void * value_ptr );
函数参数:
返回值:
调用pthread_join的线程,将被挂起,直到参数thread所代表的线程终止时为止。pthread_join是一个线程阻塞函数,调用它的函数将一直等到被等待的线程结束为止。如果value_ptr不为NULL,那么线程thread的返回值存储在该指针指向的位置。该返回值可以是由pthread_exit给出的值,或者该线程被取消而返回PTHREAD_CANCELED。
int pthread_detach(pthread_t thread);
函数参数:
个线程或者是可汇合(joinable,默认值),或者是脱离的(detached)。当一个可汇合的线程终止时,它的线程ID和退出状态将留存到另一个线程对它调用pthread_join。脱离的线程却像守护进程,当它们终止时,所有相关的资源都被释放,我们不能等待它们终止。如果一个线程需要知道另一线程什么时候终止,那就最好保持第二个线程的可汇合状态
void pthread_exit(void * rval_ptr)
函数参数:
调用在线程内调用此函数,相当于直接调用了return,但不同的是在线程中的任意函数调用了pthread_exit()都具有退出线程的同样效果。
pthread_t pthread_self();
函数返回:
利用该函数,可以在某个线程内部随时获取当前所处线程的ID,方便用来进行后续更多的判断。
程序设计流程:
利用pthread线程操作API, 创建两个线程,两个线程入口内部分别进行自身信息的打印输出,两个子线程创建之后,分别把子线程和当前主线程进行连接,此时主线程会阻塞等待两个子线程运行结束,然后正常退出。
下面给出该程序的示例,由于程序较短,直接贴在下方:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
static void *thread1_entry(void *arg)
{
printf("sub thread1 running...\r\n");
sleep(1);
pthread_exit(0);
return NULL;
}
static void *thread2_entry(void *arg)
{
printf("sub thread2 running...\r\n");
sleep(1);
pthread_exit(0);
return NULL;
}
int thread_create_demo(void)
{
pthread_t mid;
pthread_t new_th;
pthread_t new2_th;
pthread_t new3_th;
printf("\n [thread_create_demo]\r\n");
if(pthread_create(&new_th, NULL, thread1_entry, NULL) != 0)
{
perror("failed: Error creating thread1\r\n");
return 1;
}
if(pthread_create(&new2_th, NULL, thread2_entry, NULL) != 0)
{
perror("failed: Error creating thread2\r\n");
}
if(pthread_create(&new3_th, NULL, thread2_entry, NULL) != 0)
{
perror("failed: Error creating thread2\r\n");
}
mid = pthread_self();
printf("main thread: %d\r\n", main_th);
if(pthread_join(new_th, NULL) != 0)
{
perror("example_pthread_create() failed: Error in pthread_join()\n");
return 1;
}
if(pthread_join(new2_th, NULL) != 0)
{
perror("example_pthread_create() failed: Error in pthread_join()\n");
return 1;
}
if(pthread_join(new3_th, NULL) != 0)
{
perror("example_pthread_create() failed: Error in pthread_join()\n");
return 1;
}
printf("exit.\n");
return 0;
}
代码写好后,利用scons进行编译,记得在代码目录下设置好scons编译需要用到的构建文件,具体编译环境相关的操作参考上一篇文章,【ART-PI Smart 抛砖引玉 一】系统开发环境搭建与相关代码构建编译运行
编译没有错误之后,则会在sdk的userapps/root/bin目录下生成对应的elf文件。通过上一篇介绍的网口tftp,把该应用的elf文件下载到开发板的文件系统中(具体操作请参考上面第一篇的文章连接),即可运行。正常情况下,会看到程序中两个子线程和主线程对应的打印输出信息。
通过小小的线程创建例程,可以观察到,posix接口的api在Smart系统上是可以正常的支持的,后续将在线程操作的基础上,继续移植测试posix标准下IPC机制,将会以经典的生产者-消费者模型为例,来展示posix标准下的ipc运行情况。
本篇的最后,继续用一段诗来结束今天一天的疲惫吧。(●'◡'●)
“盗取荒野与星空的
人不再仰望
介乎科学和白日梦
此间诗意杀人地
煞费万物虚构之舟
去往意识碎片
不眠浪潮灰烬的意志
在酒的深处重逢”
---发光曲线乐队《荒野星》节选
我是来欣赏诗的😊
@blta 谢谢您的支持。没有科学的人文是愚昧的,没有人文的科学是危险的。共勉!