• 物联网工程师开发服务平台

MiCO OS 操作系统

MiCO 的 OS 操作系统内核功能包括:

Thread:多线程

通过 MiCO RTOS 线程控制 API 可以在系统中:定义,创建,控制和销毁线程。 线程优先级分为10级,从0-9,级数越低,优先级越高。高优先级的线程可以抢占低优先级线程,如果高优先级线程不能挂起,会导致低优先级的线程无法得到时间去运行。相同优先级的各个线程通过时间片轮转的方式分时运行,使得这些线程看起来是同时运行的。

在MiCO系统初始化时,会创建一个以函数:

int application_start(void)

为主执行体的线程,该线程的优先级是 7(MICO_APPLICATION_PRIORITY)。

一个线程可以处于以下几种状态:

  1. RUNNING,运行: 线程正在运行中,在同一个时间,MiCO RTOS 中只可能有一个线程处于运行状态。

  2. Ready,就绪: 线程已经就绪并且等待运行。一旦当前的运行线程被终止,或者挂起,所有就绪的线程中优先级最高的线程将会变成运行状态。

  3. Suspend,挂起: 线程正在等待事件(一段时间,信号量,互斥锁,消息队列)发生后,转换成就绪状态。

  4. Terminate,终止: 线程处于非活动状态,在MiCO系统的IDLE线程中,所有的非活动状态的线程所拥有的私有资源将会被自动销毁。共享资源(如通过malloc创建的内存区块)需要通过人工进行销毁。

Thread API

os_thread.c代码

#include "mico.h" 
#define os_thread_log(M, ...) custom_log("OS", M, ##__VA_ARGS__)

void thread_1(mico_thread_arg_t arg)
{
    UNUSED_PARAMETER( arg );
    while ( 1 )
    {
        os_thread_log( "This is thread 1" );
        mico_thread_sleep( 2 );
    }
}

void thread_2( mico_thread_arg_t arg )
{
    UNUSED_PARAMETER( arg );
    os_thread_log( "This is thread 2" );
    mico_thread_sleep( 4 );
    /* Make with terminate state and IDLE thread will clean resources */
    mico_rtos_delete_thread( NULL );
}

int application_start( void )
{
    OSStatus err = kNoErr;
    mico_thread_t t_handler = NULL;

    /* Create a new thread */
    err = mico_rtos_create_thread( NULL, MICO_APPLICATION_PRIORITY, "Thread 1", thread_1, 0x500, 0 );
    require_noerr_string( err, exit, "ERROR: Unable to start the thread 1." );
    while ( 1 )
    {
        /* Create a new thread, and this thread will delete its self and clean its resource */
        err = mico_rtos_create_thread( &t_handler, MICO_APPLICATION_PRIORITY, "Thread 2", thread_2, 0x500, 0 );
        require_noerr_string( err, exit, "ERROR: Unable to start the thread 2." );
        mico_rtos_thread_join( &t_handler );
    }

    exit:
    if ( err != kNoErr )
        os_thread_log( "Thread exit with err: %d", err );

    mico_rtos_delete_thread( NULL );
    return err;
}

实现:

  • 首先在 MiCO 主体线程中创建两个线程;
  • 线程 1 每次打印 log 后,休眠 2 秒钟;
  • 线程 2 每次打印 log 后,休眠 4 秒钟,并销毁线程;
  • 总体呈现两个线程交替打印的结果,线程 1 打印2次,线程 2 打印 1 次。

主要功能代码注解:

1.调用 MiCO API, 创建一个新的线程: err = mico_rtos_create_thread( NULL, MICO_APPLICATION_PRIORITY, "Thread 1", thread_1, 0x500, 0 );

2.当前线程挂起,待其它线程终止: mico_rtos_thread_join( &t_handler );

3.删除当前线程,并清除资源: mico_rtos_delete_thread( NULL );

4.当前线程休眠 2 秒钟: mico_thread_sleep( 2 );

Sem:信号量

信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量。为了完成这个过程,需要创建一个信号量VI,然后将 Acquire Semaphore VI 以及 Release Semaphore VI 分别放置在每个关键代码段的首末端,确认这些信号量VI引用的是初始创建的信号量。

通过 MiCO RTOS 信号量控制 API 可以在系统中实现:信号量的初始化,设置,获取和销毁功能。

Sem API

os_sem.c代码

#include "mico.h"
#define os_sem_log(M, ...) custom_log("OS", M, ##__VA_ARGS__)

static mico_semaphore_t os_sem = NULL;

void release_thread( mico_thread_arg_t arg )
{
    UNUSED_PARAMETER( arg );

    while ( 1 )
    {
        os_sem_log( "release semaphore" );
        mico_rtos_set_semaphore( &os_sem );
        mico_thread_sleep( 3 );
    }

    mico_rtos_delete_thread( NULL );
}

int application_start( void )
{
    OSStatus err = kNoErr;
    int semphr_fd = -1;
    os_sem_log( "test binary semaphore" );

    err = mico_rtos_init_semaphore( &os_sem, 1 ); //0/1 binary semaphore || 0/N semaphore
    require_noerr( err, exit );

    err = mico_rtos_create_thread( NULL, MICO_APPLICATION_PRIORITY, "release sem", release_thread, 0x500, 0 );
    require_noerr( err, exit );

    semphr_fd = mico_create_event_fd( os_sem );
    fd_set readfds;
    while ( 1 )
    {
        FD_ZERO( &readfds );
        FD_SET( semphr_fd, &readfds );
        select( 24, &readfds, NULL, NULL, NULL );

        if ( FD_ISSET( semphr_fd, &readfds ) )
        {
            mico_rtos_get_semaphore( &os_sem, MICO_WAIT_FOREVER ); //wait until get semaphore
            os_sem_log( "get semaphore" );
        }
    }

    exit:
    if ( err != kNoErr )
        os_sem_log( "Thread exit with err: %d", err );

    if ( os_sem != NULL )
    {
        mico_rtos_deinit_semaphore( &os_sem );
    }

    if( semphr_fd != -1 )
    {
        mico_rtos_deinit_event_fd( semphr_fd );
    }

    mico_rtos_delete_thread( NULL );
    return err;
}

实现:

  • 首先在主体线程中,创建一个新的线程,并定义一个信号量;
  • 主体线程和新线程通过信号量来获取执行权;
  • 其中,新线程打印 log 后释放信号量,此时主体线程才能执行,并打印 log,新线程休眠 3 秒钟。

主要功能代码注解:

  1. 定义一个信号量结构体: static mico_semaphore_t os_sem = NULL;

  2. 调用 MiCO API, 创建一个信号量: err = mico_rtos_init_semaphore( &os_sem, 1 ); //0/1 binary semaphore || 0/N semaphore

  3. 调用 MiCO API,释放信号量: mico_rtos_set_semaphore( &os_sem );

  4. 调用 MiCO API,获取信号量: mico_rtos_get_semaphore( &os_sem, MICO_WAIT_FOREVER ); //wait until get semaphore

  5. 销毁信号量: mico_rtos_deinit_semaphore( &os_sem );

Mutex:互斥锁

通过 MiCO RTOS 互斥锁控制 API 可以在系统中实现:互斥锁的初始化,获取,释放,和销毁功能。 互斥锁是用来保证多线程互斥的,比如,一个线程占用了某一个资源,那么别的线程就无法访问,直到这个线程离开,其他线程才开始可以利用这个资源,用来保证一段时间内只有一个线程在访问同一资源。

Mutex API

os_mutex.c 代码

#include "mico.h" 
#define os_mutex_log(M, ...) custom_log("OS", M, ##__VA_ARGS__)

//#define USE_MUTEX   //Uncommon this macro to see the different result

#ifdef USE_MUTEX
#define MUTEX_LOCK()  mico_rtos_lock_mutex(&mutex)
#define MUTEX_UNLOCK()  mico_rtos_unlock_mutex(&mutex)
#else
#define MUTEX_LOCK() 
#define MUTEX_UNLOCK()
#endif

int g_tickets = 100; //remain tickets
mico_mutex_t mutex = NULL;

char *p_name1 = "t1";
char *p_name2 = "t2";
char *p_name3 = "t3";
char *p_name4 = "t4";

void run( mico_thread_arg_t arg )
{
    char *name = (char *) arg;
    char debug[20];

    while ( 1 )
    {
        MUTEX_LOCK();
        if ( g_tickets <= 0 )
        {
            MUTEX_UNLOCK();
            goto exit;
        }

        g_tickets--;
        sprintf( debug, "Thread %s, %d\r\n", name, g_tickets );
        MicoUartSend( STDIO_UART, debug, strlen( debug ) );

        MUTEX_UNLOCK();
    }

    exit:
    os_mutex_log( "thread: %s exit now", name );
    mico_rtos_delete_thread( NULL );
}

int application_start( void )
{
    OSStatus err = kNoErr;

    /* Create a mutex*/
    err = mico_rtos_init_mutex( &mutex );
    require_noerr( err, exit );

    /* Create threads */
    err = mico_rtos_create_thread( NULL, MICO_APPLICATION_PRIORITY + 1, "t1", run, 0x800, (mico_thread_arg_t) p_name1 );
    require_noerr( err, exit );

    err = mico_rtos_create_thread( NULL, MICO_APPLICATION_PRIORITY + 1, "t2", run, 0x800, (mico_thread_arg_t) p_name2 );
    require_noerr( err, exit );

    err = mico_rtos_create_thread( NULL, MICO_APPLICATION_PRIORITY + 1, "t3", run, 0x800, (mico_thread_arg_t) p_name3 );
    require_noerr( err, exit );

    err = mico_rtos_create_thread( NULL, MICO_APPLICATION_PRIORITY + 1, "t4", run, 0x800, (mico_thread_arg_t) p_name4 );
    require_noerr( err, exit );

    exit:
    if ( err != kNoErr )
        os_mutex_log( "Thread exit with err: %d", err );

    mico_rtos_delete_thread( NULL );
    return err;
}

实现:

  • 未使用互斥锁时,四个线程打印 0-100 的票号时,顺序打乱且票号混乱;
  • 当采用了互斥锁后,四个线程按照顺序依次打印 0 - 100 的票号。

主要功能代码注解:

  1. 定义互斥锁控制 API 宏定义:
#define MUTEX_LOCK()  mico_rtos_lock_mutex(&mutex)
#define MUTEX_UNLOCK()  mico_rtos_unlock_mutex(&mutex)
  1. 调用 MiCO API, 创建一个互斥锁: err = mico_rtos_init_mutex( &mutex );/* Create a mutex*/

  2. 调用 MiCO API,获取互斥锁: mico_rtos_lock_mutex(&mutex);

  3. 调用 MiCO API,释放互斥锁: mico_rtos_unlock_mutex(&mutex);

Timer:定时器

通过 MiCO RTOS 定时器 API 可实现:系统定时器初始化,启动,停止,和销毁功能。 操作系统至少拥有一个定时器用于产生中断,进行任务调度等操作。操作系统需要知道时间,比如系统每隔一段时间来读取某个端口的状态等操作。

Timer API

代码

#include "mico.h"
#define os_timer_log(M, ...) custom_log("OS", M, ##__VA_ARGS__)

mico_timer_t timer_handle;

void destroy_timer( void );
void alarm( void* arg );

void destroy_timer( void )
{
  mico_stop_timer( &timer_handle );
  mico_deinit_timer( &timer_handle );
}

void alarm( void* arg )
{
  int* count = (int*)arg;
  os_timer_log("time is coming,value = %d", (*count)++ );

  if( *count == 10 )
    destroy_timer();
}

int application_start( void )
{
  OSStatus err = kNoErr;
  os_timer_log("timer demo");
  int arg = 0;

  err = mico_init_timer(&timer_handle, 1000, alarm, &arg);
  require_noerr(err, exit);

  err = mico_start_timer(&timer_handle);
  require_noerr(err, exit);

  mico_thread_sleep( MICO_NEVER_TIMEOUT );

exit:
  if( err != kNoErr )
    os_timer_log( "Thread exit with err: %d", err );

  mico_rtos_delete_thread( NULL );
  return err;
}

实现:

  • 通过创建和启动一个系统定时器,实现以 1 秒钟为周期的定时中断,每进一次中断,变量 count 累加一,直到累加到 10 ,停止定时器并销毁。

主要功能代码注解:

  1. 调用 MiCO API,创建一个 RTOS 定时器: err = mico_init_timer(&timer_handle, 1000, alarm, &arg);

  2. 调用 MiCO API, 启动一个 RTOS 定时器: err = mico_start_timer(&timer_handle);

  3. 调用 MiCO API,停止一个 RTOS 定时器: mico_stop_timer( &timer_handle );

  4. 调用 MiCO API,销毁一个 RTOS 定时器: mico_deinit_timer( &timer_handle );

Queue:消息队列

消息队列是操作系统中线程之间实现数据交换的常用手段。

Queue API

代码

#include "mico.h"
#define os_queue_log(M, ...) custom_log("OS", M, ##__VA_ARGS__)

static mico_queue_t os_queue = NULL;
typedef struct _msg
{
    int value;
} msg_t;

void receiver_thread( mico_thread_arg_t arg )
{
    UNUSED_PARAMETER( arg );

    OSStatus err;
    msg_t received = { 0 };

    while ( 1 )
    {
        /*Wait until queue has data*/
        err = mico_rtos_pop_from_queue( &os_queue, &received, MICO_WAIT_FOREVER );
        require_noerr( err, exit );

        os_queue_log( "Received data from queue:value = %d",received.value );
    }

    exit:
    if ( err != kNoErr )
        os_queue_log( "Receiver exit with err: %d", err );

    mico_rtos_delete_thread( NULL );
}

void sender_thread( mico_thread_arg_t arg )
{
    UNUSED_PARAMETER( arg );
    OSStatus err = kNoErr;

    msg_t my_message = { 0 };

    while ( 1 )
    {
        my_message.value++;
        mico_rtos_push_to_queue( &os_queue, &my_message, MICO_WAIT_FOREVER );
        require_noerr( err, exit );

        os_queue_log( "send data to queue" );
        mico_thread_sleep( 1 );
    }

    exit:
    if ( err != kNoErr )
        os_queue_log( "Sender exit with err: %d", err );

    mico_rtos_delete_thread( NULL );
}

int application_start( void )
{
    OSStatus err = kNoErr;

    err = mico_rtos_init_queue( &os_queue, "queue", sizeof(msg_t), 3 );
    require_noerr( err, exit );

    err = mico_rtos_create_thread( NULL, MICO_APPLICATION_PRIORITY, "receiver", receiver_thread, 0x500, 0 );
    require_noerr( err, exit );

    err = mico_rtos_create_thread( NULL, MICO_APPLICATION_PRIORITY, "sender", sender_thread, 0x500, 0 );
    require_noerr( err, exit );

    exit:
    if ( err != kNoErr )
        os_queue_log( "Thread exit with err: %d", err );

    mico_rtos_delete_thread( NULL );

    return err;
}

实现:

  • 系统创建两个线程,一个线程向消息队列中发送数据,一个线程从消息队列接收数据,并打印数据信息。
  • 其中,发送线程每次发送的数据依次累加 1,且每次线程休眠 1 秒钟。

主要功能代码注解:

  1. 调用 MiCO API,初始化一个消息队列:
err = mico_rtos_init_queue( &os_queue, "queue", sizeof(msg_t), 3 );
  1. 调用 MiCO API, 向消息队列中写入数据:
mico_rtos_push_to_queue( &os_queue, &my_message, MICO_WAIT_FOREVER );
  1. 调用 MiCO API,从消息队列读出数据: err = mico_rtos_pop_from_queue( &os_queue, &received, MICO_WAIT_FOREVER );

  2. 调用 MiCO API,销毁一个 RTOS 定时器: mico_deinit_timer( &timer_handle );

文本导读目录