7.9. PTHREAD API

Overview

SDK中提供了两种操作系统API,一种是基于FreeRTOS原接口进行再次封装的API(这里简称为OS API), 在SDK有更好的兼容性,所以SDK中大量采用了这类API(具体请参考 OS API );另一种为POSIX Threads(这里简称为pthread api);

7.9.1. DEMO

使用工程:示例代码见 apps/common/example/system/os/pthreads_api/main.c,测试时需要在 apps/demo/demo_DevKitBoard/include/demo_config.h ,开启宏 USE_PTHREAD_API_TEST

示例说明

展示了PTHREAD API基本使用方法,包括任务创建、信号量、互斥量的使用和消息队列的使用等,主要示例包括:

  • posix_mutex_test(); 互斥量使用示例

  • posix_queue_test(); 消息队列使用示例

  • posix_sem_test(); 信号量使用示例

7.9.2. 线程(Task)

线程创建

函数

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*startroutine)(void *), void *arg)

描述

创建线程

参数

thread:指向线程句柄的指针,不能为NULL attr: 指向线程属性的指针,如果使用NULL,则使用默认的线程属性 startroutine:线程入口函数地址 arg: 传递给线程入口函数的参数

返回值

0:成功 其他:失败

例子

#include <pthread.h>

static pthread_t thread1;
static pthread_t thread2;

static void* thread_entry(void* parameter)
{
    int cnt = 0;
    int data = (int) parameter;

    while (1)
    {
        printf("data : %d, cnt : %d\n", data, cnt++);

        sleep(5);
    }

    return NULL;
}

int application_init()
{
    int ret;
    int data1 = 1;
    int data2 = 2;

    /** 创建线程1*/
    ret = pthread_create(&thread1, NULL, thread_entry, (void*)data1);
    if(0 != ret)
        printf("pthread_create failed! error code is %d\n", ret);

    /** 创建线程2*/
    ret = pthread_create(&thread2, NULL, thread_entry, (void*)data2);
    if(0 != ret)
        printf("pthread_create failed! error code is %d\n", ret);

    return 0;
}

阻塞等待线程退出

函数

int pthread_join(pthread_t thread, void **retval);

描述

阻塞等待线程退出

参数

thread:线程句柄 retval: 用户定义的指针,用来存储被等待线程的返回值地址

返回值

0:成功 其他:失败

例子

#include <pthread.h>

static pthread_t thread1;
static pthread_t thread2;

static void* thread_entry1(void* parameter)
{
    int cnt = 0;
    int data = (int) parameter;

    for(int i; i < 4; i++)
    {
        printf("data : %d, cnt : %d\n", data, cnt++);

        sleep(5);
    }

    printf("thread1 exited!\n");
    return NULL;
}

static void* thread_entry2(void* parameter)
{
    int cnt = 0;
    int data = (int) parameter;

    /** 阻塞等待线程1运行退出 */
    pthread_join(thread1, NULL);

    for(int i; i < 4; i++)
    {
        printf("data : %d, cnt : %d\n", data, cnt++);

        sleep(5);
    }

    printf("thread1 exited!\n");
    return NULL;
}

int application_init()
{
    int ret;
    int data1 = 1;
    int data2 = 2;

    /** 创建线程1*/
    ret = pthread_create(&thread1, NULL, thread_entry1, (void*)data1);
    if(0 != ret)
        printf("pthread_create failed! error code is %d\n", ret);

    /** 创建线程2*/
    ret = pthread_create(&thread2, NULL, thread_entry2, (void*)data2);
    if(0 != ret)
        printf("pthread_create failed! error code is %d\n", ret);

    return 0;
}

退出线程

函数

void pthread_exit(void *value_ptr)

描述

退出线程

参数

value_ptr: 用户定义的指针,用来存储被等待线程的返回值地址

返回值

0:成功 其他:失败

例子

#include <pthread.h>

static pthread_t thread;

static void* thread_entry(void* parameter)
{
    int cnt = 0;
    int data = (int) parameter;

    while (1)
    {
        printf("data : %d, cnt : %d\n", data, cnt++);

        sleep(5);

        pthread_exit(NULL); //退出线程
    }

    printf("thread exited!\n");

    return NULL;
}

int application_init()
{
    int ret;
    int data1 = 1;

    /** 创建线程*/
    ret = pthread_create(&thread, NULL, thread_entry, (void*)data1);
    if(0 != ret)
        printf("pthread_create failed! error code is %d\n", ret);

    return 0;
}

7.9.3. 消息队列(Queue)

创建消息队列

函数

mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr *attr);

描述

创建消息队列

参数

name : 消息队列名称 oflag :消息队列打开方式 mode : attr :

返回值

非NULL:返回消息队列句柄 NULL:失败

发送消息

函数

int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio);

描述

发送消息

参数

mqdes : 消息队列句柄 msg_ptr :指向要发送的消息的指针 msg_len : 发送的消息的长度 msg_prio : 不支持,忽略

返回值

0:成功 其他:失败

接收消息

例子

static mqd_t mqID;

//发送线程
static void *thread_send(void *args)
{
    char msg[] = "This is a message for test!";
    mqd_t *sendID = (mqd_t *)args;

    while (1) {
        if (mq_send(*sendID, msg, sizeof(msg), 0) < 0) {
            printf("send msg err!\n");
            //终止当前线程
            pthread_exit(NULL);
        }

        os_time_dly(100);
    }

    return (void *)0;
}

//接收线程
static void *thread_rec(void *args)
{
    char buf[128] ;
    mqd_t *recID = (mqd_t *)args;

    while (1) {
        if (mq_receive(*recID, buf, sizeof(buf), NULL) < 0) {
            printf("rec msg err!\r\n");

            //终止当前线程
            pthread_exit(NULL);
        }

        printf("Message received :(%s)\n", buf);
    }

    return (void *)0;
}

static void posix_queue_test(void)
{
    pthread_t send;
    pthread_t rec;
    struct mq_attr mqAttr;
    pthread_attr_t attr = {0};
    struct sched_param param;
    int ret;

    //创建消息队列
    mqID = mq_open("/mQueue_test", O_RDWR | O_CREAT, 0666, NULL); //队列消息名字需要符合POSIX IPC的名字规则
    if (mqID < 0) {
        printf("mq_open err!!!\r\n");
        return;
    }

    //获取消息队列属性
    if (mq_getattr(mqID, &mqAttr) < 0) {
        printf("mq_getattr err!!!\r\n");
        return;
    }

    printf("mq_flags:%d\r\n", mqAttr.mq_flags);
    printf("mq_maxmsg:%d\r\n", mqAttr.mq_maxmsg);
    printf("mq_msgsize:%d\r\n", mqAttr.mq_msgsize);
    printf("mq_curmsgs:%d\r\n", mqAttr.mq_curmsgs);

    //初始化线程属性变量
    pthread_attr_init(&attr);

    //设置优先级
    pthread_attr_getschedparam(&attr, &param);
    param.sched_priority = 10;

    //设置优先级
    pthread_attr_setschedparam(&attr, &param);

    //采用默认优先级时,设置为NULL
    ret = pthread_create(&send, &attr, thread_send, &mqID);
    //ret = pthread_create(&send, NULL,thread_send, &mqID);
    if (ret) {
        printf("pthread_create send error!!!\r\n");
    }

    pthread_create(&rec, NULL, thread_rec, &mqID);
    if (ret) {
        printf("pthread_create send error!!!\r\n");
    }
}

7.9.4. 信号量(Semaphore)

初始化信号量

函数

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

描述

初始化信号量

参数

sem: 信号量句柄 pshared: 忽略 value: 信号量初始值,表示信号量资源的可用数量

返回值

0:成功 其他:失败

获取信号量

函数

int sem_wait(sem_t *sem);

描述

阻塞方式等待信号量

参数

sem: 信号量句柄

返回值

0:成功 其他:失败

函数

int sem_trywait(sem_t *sem);

描述

非阻塞方式等待信号量

参数

sem: 信号量句柄

返回值

0:成功 其他:失败

释放信号量

函数

int sem_post(sem_t *sem);

描述

释放信号量

参数

sem: 信号量句柄

返回值

0:成功 其他:失败

例子

static sem_t psem;
static pthread_t waitSem;
static pthread_t postSem;

static void *thread_wait_sem(void *args)
{
    while (1) {
        puts(">>>>>>>[0]thread_wait_sem : wait sem!");
        sem_wait(&psem);
        puts(">>>>>>>[2]thread_wait_sem : get sem!");
    }
    return (void *)0;
}

static void *thread_post_sem(void *args)
{
    while (1) {
        os_time_dly(1000);
        sem_post(&psem);
        puts(">>>>>>>[1]thread_post_sem : post sem!");
    }

    return (void *)0;
}

static void posix_sem_test(void)
{
    int ret;

    ret = sem_init(&psem, 0, 0);
    if (ret) {
        puts("sem_init err!!!");
    }

    pthread_create(&waitSem, NULL, thread_wait_sem, NULL);

    pthread_create(&postSem, NULL, thread_post_sem, NULL);

    os_time_dly(50);

}

7.9.5. 互斥锁(Mutex)

初始化互斥锁

函数

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);

描述

初始化互斥锁

参数

mutex: 互斥锁句柄 attr: 指向互斥锁属性的指针,若该指针NULL,则使用默认的属性。

返回值

0:成功 其他:失败

互斥锁上锁

函数

int pthread_mutex_lock(pthread_mutex_t *mutex);

描述

阻塞方式给互斥锁上锁 ,如果互斥锁mutex被其他线程上锁持有,当前线程将阻塞等待。

参数

mutex: 互斥锁句柄

返回值

0:成功 其他:失败

函数

int pthread_mutex_trylock(pthread_mutex_t *mutex);

描述

非阻塞方式给互斥锁上锁 ,如果互斥锁mutex已经被上锁,当前线程不会阻塞等待,而是马上返回错误码

参数

mutex: 互斥锁句柄

返回值

0:成功 其他:失败

互斥锁解锁

函数

int pthread_mutex_unlock(pthread_mutex_t *mutex);

描述

互斥锁解锁

参数

mutex: 互斥锁句柄

返回值

0:成功 其他:失败

销毁互斥锁

函数

int pthread_mutex_destroy(pthread_mutex_t *mutex);

描述

销毁互斥锁

参数

mutex: 互斥锁句柄

返回值

0:成功 其他:失败

例子

static pthread_mutex_t mutex;
static pthread_t p1, p2;

extern void os_time_dly(int tick);

static void *func1(void *arg)
{
    char *str = (char *)arg;

    //获取互斥锁
    pthread_mutex_lock(&mutex);

    while (*str != '\0') {
        printf("%c\n", *str);
        str++;
    }
    puts("\n");

    //释放互斥锁
    pthread_mutex_unlock(&mutex);

    return (void *)0;
}

static void *func2(void *arg)
{
    char *str = (char *)arg;

    //获取互斥锁
    pthread_mutex_lock(&mutex);

    while (*str != '\0') {
        printf("%c\n", *str);
        str++;
    }
    puts("\n");

    //释放互斥锁
    pthread_mutex_unlock(&mutex);

    return (void *)0;
}

static void posix_mutex_test(void)
{
    char *str1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    char *str2 = "abcdefghijklmnopqrstuvwxyz";
    int err;

    pthread_mutex_init(&mutex, NULL);

    if ((err = pthread_create(&p1, NULL, func1, str1)) != 0) {
        printf("[0]pthread_create fail\n");
    }

    if ((err = pthread_create(&p2, NULL, func2, str2)) != 0) {
        printf("[1]pthread_create fail\n");
    }

}