semaphore_buffer_worker.c 7.5 KB
Newer Older
B
Bernard Xiong 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/*
 * 程序清单:信号量实现生产者消费者间的互斥
 *
 * 在这个程序中,会创建两个线程,一个是生成者线程worker一个是消费者线程thread
 *
 * 在数据信息生产、消费的过程中,worker负责把数据将写入到环形buffer中,而thread
 * 则从环形buffer中读出。
 */
#include <rtthread.h>
#include "tc_comm.h"

/* 一个环形buffer的实现 */
struct rb
{
G
Grissiom 已提交
15 16 17
    rt_uint16_t read_index, write_index;
    rt_uint8_t *buffer_ptr;
    rt_uint16_t buffer_size;
B
Bernard Xiong 已提交
18 19 20 21 22 23 24 25
};

/* 指向信号量控制块的指针 */
static rt_sem_t sem = RT_NULL;
/* 指向线程控制块的指针 */
static rt_thread_t tid = RT_NULL, worker = RT_NULL;

/* 环形buffer的内存块(用数组体现出来) */
G
Grissiom 已提交
26 27
#define BUFFER_SIZE        256
#define BUFFER_ITEM        32
B
Bernard Xiong 已提交
28 29 30 31 32 33
static rt_uint8_t working_buffer[BUFFER_SIZE];
struct rb working_rb;

/* 初始化环形buffer,size指的是buffer的大小。注:这里并没对数据地址对齐做处理 */
static void rb_init(struct rb* rb, rt_uint8_t *pool, rt_uint16_t size)
{
G
Grissiom 已提交
34
    RT_ASSERT(rb != RT_NULL);
B
Bernard Xiong 已提交
35

G
Grissiom 已提交
36 37
    /* 对读写指针清零*/
    rb->read_index = rb->write_index = 0;
B
Bernard Xiong 已提交
38

G
Grissiom 已提交
39 40 41
    /* 设置环形buffer的内存数据块 */
    rb->buffer_ptr = pool;
    rb->buffer_size = size;
B
Bernard Xiong 已提交
42 43 44 45 46
}

/* 向环形buffer中写入数据 */
static rt_bool_t rb_put(struct rb* rb, const rt_uint8_t *ptr, rt_uint16_t length)
{
G
Grissiom 已提交
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
    rt_size_t size;

    /* 判断是否有足够的剩余空间 */
    if (rb->read_index > rb->write_index)
        size = rb->read_index - rb->write_index;
    else
        size = rb->buffer_size - rb->write_index + rb->read_index;

    /* 没有多余的空间 */
    if (size < length) return RT_FALSE;

    if (rb->read_index > rb->write_index)
    {
        /* read_index - write_index 即为总的空余空间 */
        memcpy(&rb->buffer_ptr[rb->write_index], ptr, length);
        rb->write_index += length;
    }
    else
    {
        if (rb->buffer_size - rb->write_index > length)
        {
            /* write_index 后面剩余的空间有足够的长度 */
            memcpy(&rb->buffer_ptr[rb->write_index], ptr, length);
            rb->write_index += length;
        }
        else
        {
            /*
             * write_index 后面剩余的空间不存在足够的长度,需要把部分数据复制到
             * 前面的剩余空间中
             */
            memcpy(&rb->buffer_ptr[rb->write_index], ptr,
                   rb->buffer_size - rb->write_index);
            memcpy(&rb->buffer_ptr[0], &ptr[rb->buffer_size - rb->write_index],
                   length - (rb->buffer_size - rb->write_index));
            rb->write_index = length - (rb->buffer_size - rb->write_index);
        }
    }

    return RT_TRUE;
B
Bernard Xiong 已提交
87 88 89 90 91
}

/* 从环形buffer中读出数据 */
static rt_bool_t rb_get(struct rb* rb, rt_uint8_t *ptr, rt_uint16_t length)
{
G
Grissiom 已提交
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
    rt_size_t size;

    /* 判断是否有足够的数据 */
    if (rb->read_index > rb->write_index)
        size = rb->buffer_size - rb->read_index + rb->write_index;
    else
        size = rb->write_index - rb->read_index;

    /* 没有足够的数据 */
    if (size < length) return RT_FALSE;

    if (rb->read_index > rb->write_index)
    {
        if (rb->buffer_size - rb->read_index > length)
        {
            /* read_index的数据足够多,直接复制 */
            memcpy(ptr, &rb->buffer_ptr[rb->read_index], length);
            rb->read_index += length;
        }
        else
        {
            /* read_index的数据不够,需要分段复制 */
            memcpy(ptr, &rb->buffer_ptr[rb->read_index],
                   rb->buffer_size - rb->read_index);
            memcpy(&ptr[rb->buffer_size - rb->read_index], &rb->buffer_ptr[0],
                   length - rb->buffer_size + rb->read_index);
            rb->read_index = length - rb->buffer_size + rb->read_index;
        }
    }
    else
    {
        /*
         * read_index要比write_index小,总的数据量够(前面已经有总数据量的判
         * 断),直接复制出数据。
         */
        memcpy(ptr, &rb->buffer_ptr[rb->read_index], length);
        rb->read_index += length;
    }

    return RT_TRUE;
B
Bernard Xiong 已提交
132 133 134 135 136
}

/* 生产者线程入口 */
static void thread_entry(void* parameter)
{
G
Grissiom 已提交
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
    rt_bool_t result;
    rt_uint8_t data_buffer[BUFFER_ITEM + 1];

    while (1)
    {
        /* 持有信号量 */
        rt_sem_take(sem, RT_WAITING_FOREVER);
        /* 从环buffer中获得数据 */
        result = rb_get(&working_rb, &data_buffer[0], BUFFER_ITEM);
        /* 释放信号量 */
        rt_sem_release(sem);
        data_buffer[BUFFER_ITEM] = '\0';

        if (result == RT_TRUE)
        {
            /* 获取数据成功,打印数据 */
            rt_kprintf("%s\n", data_buffer);
        }

        /* 做一个5 OS Tick的休眠 */
        rt_thread_delay(5);
    }
B
Bernard Xiong 已提交
159 160 161 162 163
}

/* worker线程入口 */
static void worker_entry(void* parameter)
{
G
Grissiom 已提交
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
    rt_bool_t result;
    rt_uint32_t index, setchar;
    rt_uint8_t  data_buffer[BUFFER_ITEM];

    setchar = 0x21;
    while (1)
    {
        /* 构造数据 */
        for(index = 0; index < BUFFER_ITEM; index++)
        {
            data_buffer[index] = setchar;
            if (++setchar == 0x7f)
                setchar = 0x21;
        }

        /* 持有信号量 */
        rt_sem_take(sem, RT_WAITING_FOREVER);
        /* 把数据放到环形buffer中 */
        result = rb_put(&working_rb, &data_buffer[0], BUFFER_ITEM);
        /* 释放信号量 */
        rt_sem_release(sem);

        /* 放入成功,做一个10 OS Tick的休眠 */
        rt_thread_delay(10);
    }
B
Bernard Xiong 已提交
189 190 191 192
}

int semaphore_buffer_worker_init()
{
G
Grissiom 已提交
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
    /* 初始化ring buffer */
    rb_init(&working_rb, working_buffer, BUFFER_SIZE);

    /* 创建信号量 */
    sem = rt_sem_create("sem", 1, RT_IPC_FLAG_FIFO);
    if (sem == RT_NULL)
    {
        tc_stat(TC_STAT_END | TC_STAT_FAILED);
        return 0;
    }

    /* 创建线程1 */
    tid = rt_thread_create("thread",
                           thread_entry, RT_NULL, /* 线程入口是thread_entry, 入口参数是RT_NULL */
                           THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
    if (tid != RT_NULL)
        rt_thread_startup(tid);
    else
        tc_stat(TC_STAT_END | TC_STAT_FAILED);

    /* 创建线程2 */
    worker = rt_thread_create("worker",
                              worker_entry, RT_NULL, /* 线程入口是worker_entry, 入口参数是RT_NULL */
                              THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
    if (worker != RT_NULL)
        rt_thread_startup(worker);
    else
        tc_stat(TC_STAT_END | TC_STAT_FAILED);

    return 0;
B
Bernard Xiong 已提交
223 224 225 226 227
}

#ifdef RT_USING_TC
static void _tc_cleanup()
{
G
Grissiom 已提交
228 229
    /* 调度器上锁,上锁后,将不再切换到其他线程,仅响应中断 */
    rt_enter_critical();
B
Bernard Xiong 已提交
230

G
Grissiom 已提交
231 232 233
    /* 删除信号量 */
    if (sem != RT_NULL)
        rt_sem_delete(sem);
B
Bernard Xiong 已提交
234

G
Grissiom 已提交
235 236 237 238 239
    /* 删除线程 */
    if (tid != RT_NULL && tid->stat != RT_THREAD_CLOSE)
        rt_thread_delete(tid);
    if (worker != RT_NULL && worker->stat != RT_THREAD_CLOSE)
        rt_thread_delete(worker);
B
Bernard Xiong 已提交
240

G
Grissiom 已提交
241 242
    /* 调度器解锁 */
    rt_exit_critical();
B
Bernard Xiong 已提交
243

G
Grissiom 已提交
244 245
    /* 设置TestCase状态 */
    tc_done(TC_STAT_PASSED);
B
Bernard Xiong 已提交
246 247 248 249
}

int _tc_semaphore_buffer_worker()
{
G
Grissiom 已提交
250 251 252
    /* 设置TestCase清理回调函数 */
    tc_cleanup(_tc_cleanup);
    semaphore_buffer_worker_init();
B
Bernard Xiong 已提交
253

G
Grissiom 已提交
254 255
    /* 返回TestCase运行的最长时间 */
    return 100;
B
Bernard Xiong 已提交
256 257 258 259 260 261 262
}
/* 输出函数命令到finsh shell中 */
FINSH_FUNCTION_EXPORT(_tc_semaphore_buffer_worker, a buffer worker with semaphore example);
#else
/* 用户应用入口 */
int rt_application_init()
{
G
Grissiom 已提交
263
    semaphore_buffer_worker_init();
B
Bernard Xiong 已提交
264

G
Grissiom 已提交
265
    return 0;
B
Bernard Xiong 已提交
266 267
}
#endif