diff --git a/examples/kernel/SConscript b/examples/kernel/SConscript index 1020d7dfe..e3325b3bf 100644 --- a/examples/kernel/SConscript +++ b/examples/kernel/SConscript @@ -17,6 +17,8 @@ semaphore_static.c semaphore_dynamic.c semaphore_priority.c semaphore_buffer_worker.c +semaphore_producer_consumer.c +mutex_simple.c heap_malloc.c heap_realloc.c """) diff --git a/examples/kernel/mutex_simple.c b/examples/kernel/mutex_simple.c new file mode 100644 index 000000000..574404a97 --- /dev/null +++ b/examples/kernel/mutex_simple.c @@ -0,0 +1,108 @@ +/* + * 程序清单: + */ +#include +#include "tc_comm.h" + +/* 指向线程控制块的指针 */ +static rt_thread_t tid1 = RT_NULL; +static rt_thread_t tid2 = RT_NULL; +static rt_thread_t tid3 = RT_NULL; + +/* 线程1入口 */ +static void thread1_entry(void* parameter) +{ + while (1) + { + } +} + +/* 线程2入口 */ +static void thread2_entry(void* parameter) +{ + while (1) + { + } +} + +/* 线程3入口 */ +static void thread3_entry(void* parameter) +{ + while (1) + { + } +} + +int mutex_simple_init() +{ + /* 创建线程1 */ + tid1 = rt_thread_create("t1", + thread1_entry, RT_NULL, /* 线程入口是thread1_entry, 入口参数是RT_NULL */ + THREAD_STACK_SIZE, THREAD_PRIORITY - 1, THREAD_TIMESLICE); + if (tid1 != RT_NULL) + rt_thread_startup(tid1); + else + tc_stat(TC_STAT_END | TC_STAT_FAILED); + + /* 创建线程2 */ + tid2 = rt_thread_create("t2", + thread2_entry, RT_NULL, /* 线程入口是thread2_entry, 入口参数是RT_NULL */ + THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); + if (tid2 != RT_NULL) + rt_thread_startup(tid2); + else + tc_stat(TC_STAT_END | TC_STAT_FAILED); + + /* 创建线程3 */ + tid3 = rt_thread_create("t3", + thread3_entry, RT_NULL, /* 线程入口是thread3_entry, 入口参数是RT_NULL */ + THREAD_STACK_SIZE, THREAD_PRIORITY + 1, THREAD_TIMESLICE); + if (tid3 != RT_NULL) + rt_thread_startup(tid3); + else + tc_stat(TC_STAT_END | TC_STAT_FAILED); + + return 0; +} + +#ifdef RT_USING_TC +static void _tc_cleanup() +{ + /* 调度器上锁,上锁后,将不再切换到其他线程,仅响应中断 */ + rt_enter_critical(); + + /* 删除线程 */ + if (tid1 != RT_NULL && tid1->stat != RT_THREAD_CLOSE) + rt_thread_delete(tid1); + if (tid2 != RT_NULL && tid2->stat != RT_THREAD_CLOSE) + rt_thread_delete(tid2); + if (tid3 != RT_NULL && tid3->stat != RT_THREAD_CLOSE) + rt_thread_delete(tid3); + + /* 调度器解锁 */ + rt_exit_critical(); + + /* 设置TestCase状态 */ + tc_done(TC_STAT_PASSED); +} + +int _tc_mutex_simple() +{ + /* 设置TestCase清理回调函数 */ + tc_cleanup(_tc_cleanup); + mutex_simple_init(); + + /* 返回TestCase运行的最长时间 */ + return 100; +} +/* 输出函数命令到finsh shell中 */ +FINSH_FUNCTION_EXPORT(_tc_mutex_simple, sime mutex example); +#else +/* 用户应用入口 */ +int rt_application_init() +{ + mutex_simple_init(); + + return 0; +} +#endif diff --git a/examples/kernel/semaphore_buffer_worker.c b/examples/kernel/semaphore_buffer_worker.c index 8dcf24206..96afb43dd 100644 --- a/examples/kernel/semaphore_buffer_worker.c +++ b/examples/kernel/semaphore_buffer_worker.c @@ -1,82 +1,217 @@ +/* + * 程序清单:信号量实现生产者消费者间的互斥 + * + * 在这个程序中,会创建两个线程,一个是生成者线程worker一个是消费者线程thread + * + * 在数据信息生产、消费的过程中,worker负责把数据将写入到环形buffer中,而thread + * 则从环形buffer中读出。 + */ #include #include "tc_comm.h" -static rt_sem_t sem; -static rt_thread_t t1, worker; - -#define BUFFER_SIZE 256 -#define DATA_ITEM_SIZE 32 - -static rt_uint8_t working_buffer[BUFFER_SIZE]; -static rt_uint16_t write_index, read_index; - -static void thread1_entry(void* parameter) +/* 一个环形buffer的实现 */ +struct rb { - rt_err_t result; - rt_uint16_t next_index; - rt_uint8_t data[DATA_ITEM_SIZE]; + rt_uint16_t read_index, write_index; + rt_uint8_t *buffer_ptr; + rt_uint16_t buffer_size; +}; + +/* 指向信号量控制块的指针 */ +static rt_sem_t sem = RT_NULL; +/* 指向线程控制块的指针 */ +static rt_thread_t tid = RT_NULL, worker = RT_NULL; + +/* 环形buffer的内存块(用数组体现出来) */ +#define BUFFER_SIZE 256 +#define BUFFER_ITEM 32 +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) +{ + RT_ASSERT(rb != RT_NULL); + + /* 对读写指针清零*/ + rb->read_index = rb->write_index = 0; + + /* 设置环形buffer的内存数据块 */ + rb->buffer_ptr = pool; + rb->buffer_size = size; +} + +/* 向环形buffer中写入数据 */ +static rt_bool_t rb_put(struct rb* rb, const rt_uint8_t *ptr, rt_uint16_t length) +{ + 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; +} + +/* 从环形buffer中读出数据 */ +static rt_bool_t rb_get(struct rb* rb, rt_uint8_t *ptr, rt_uint16_t length) +{ + 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; +} + +/* 生产者线程入口 */ +static void thread_entry(void* parameter) +{ + rt_bool_t result; + rt_uint8_t data_buffer[BUFFER_ITEM]; while (1) { - /* take a semaphore */ - result = rt_sem_take(sem, RT_WAITING_FOREVER); - if (result != RT_EOK) + /* 持有信号量 */ + rt_sem_take(sem, RT_WAITING_FOREVER); + /* 从环buffer中获得数据 */ + result = rb_get(&working_rb, &data_buffer[0], BUFFER_ITEM); + /* 释放信号量 */ + rt_sem_release(sem); + + if (result == RT_TRUE) { - tc_done(TC_STAT_FAILED); - return; + /* 获取数据成功,打印数据 */ + rt_kprintf("%s\n", data_buffer); } - /* read buffer */ - - /* release semaphore */ - rt_sem_release(sem); + /* 做一个5 OS Tick的休眠 */ + rt_thread_delay(5); } } -static void worker_thread_entry(void* parameter) +/* worker线程入口 */ +static void worker_entry(void* parameter) { - rt_err_t result; - rt_uint16_t next_index; - rt_uint8_t data[DATA_ITEM_SIZE]; + rt_bool_t result; + rt_uint32_t index, setchar; + rt_uint8_t data_buffer[BUFFER_ITEM]; + setchar = 0x21; while (1) { - /* take a semaphore */ - result = rt_sem_take(sem, RT_WAITING_FOREVER); - if (result != RT_EOK) + /* 构造数据 */ + for(index = 0; index < BUFFER_ITEM; index++) { - tc_done(TC_STAT_FAILED); - return; + data_buffer[index] = setchar; + if (++setchar == 0x7f) + setchar = 0x21; } - /* write buffer */ - - /* release semaphore */ + /* 持有信号量 */ + 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); } } int semaphore_buffer_worker_init() { - sem = rt_sem_create("sem", 0, RT_IPC_FLAG_FIFO); + /* 初始化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; } - write_index = read_index = 0; - - t1 = rt_thread_create("t1", - thread1_entry, RT_NULL, - THREAD_STACK_SIZE, THREAD_PRIORITY + 1, THREAD_TIMESLICE); - if (t1 != RT_NULL) - rt_thread_startup(t1); + /* 创建线程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_thread_entry, RT_NULL, + worker_entry, RT_NULL, /* 线程入口是worker_entry, 入口参数是RT_NULL */ THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); if (worker != RT_NULL) rt_thread_startup(worker); @@ -89,29 +224,39 @@ int semaphore_buffer_worker_init() #ifdef RT_USING_TC static void _tc_cleanup() { - /* lock scheduler */ + /* 调度器上锁,上锁后,将不再切换到其他线程,仅响应中断 */ rt_enter_critical(); - /* delete t1, t2 and worker thread */ - rt_thread_delete(t1); - rt_thread_delete(worker); + /* 删除信号量 */ + if (sem != RT_NULL) + rt_sem_delete(sem); - tc_stat(TC_STAT_PASSED); + /* 删除线程 */ + 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); - /* unlock scheduler */ + /* 调度器解锁 */ rt_exit_critical(); + + /* 设置TestCase状态 */ + tc_done(TC_STAT_PASSED); } int _tc_semaphore_buffer_worker() { - /* set tc cleanup */ + /* 设置TestCase清理回调函数 */ tc_cleanup(_tc_cleanup); semaphore_buffer_worker_init(); - return 50; + /* 返回TestCase运行的最长时间 */ + return 100; } -FINSH_FUNCTION_EXPORT(_tc_semaphore_buffer_worker, two threads working on a buffer example); +/* 输出函数命令到finsh shell中 */ +FINSH_FUNCTION_EXPORT(_tc_semaphore_buffer_worker, a buffer worker with semaphore example); #else +/* 用户应用入口 */ int rt_application_init() { semaphore_buffer_worker_init(); diff --git a/examples/kernel/semaphore_producer_consumer.c b/examples/kernel/semaphore_producer_consumer.c new file mode 100644 index 000000000..5ea98fbea --- /dev/null +++ b/examples/kernel/semaphore_producer_consumer.c @@ -0,0 +1,154 @@ +/* + * 程序清单:生产者消费者例子 + * + * 这个例子中将创建两个线程用于实现生产者消费者问题 + */ +#include +#include "tc_comm.h" + +/* 定义最大5个元素能够被产生 */ +#define MAXSEM 5 + +/* 用于放置生产的整数数组 */ +rt_uint32_t array[MAXSEM]; +/* 指向生产者、消费者在array数组中的读写位置 */ +static rt_uint32_t set, get; + +/* 指向线程控制块的指针 */ +static rt_thread_t producer_tid = RT_NULL; +static rt_thread_t consumer_tid = RT_NULL; + +struct rt_semaphore sem_lock; +struct rt_semaphore sem_empty, sem_full; + +/* 生成者线程入口 */ +void producer_thread_entry(void* parameter) +{ + int cnt = 0; + + /* 运行100次 */ + while( cnt < 100) + { + /* 获取一个空位 */ + rt_sem_take(&sem_empty, RT_WAITING_FOREVER); + + /* 修改array内容,上锁 */ + rt_sem_take(&sem_lock, RT_WAITING_FOREVER); + array[set%MAXSEM] = cnt + 1; + rt_kprintf("the producer generates a number: %d\n", array[set%MAXSEM]); + set++; + rt_sem_release(&sem_lock); + + /* 发布一个满位 */ + rt_sem_release(&sem_full); + cnt++; + + /* 暂停一段时间 */ + rt_thread_delay(50); + } + + rt_kprintf("the producer exit!\n"); +} + +/* 消费者线程入口 */ +void consumer_thread_entry(void* parameter) +{ + rt_uint32_t no; + rt_uint32_t sum; + + /* 第n个线程,由入口参数传进来 */ + no = (rt_uint32_t)parameter; + + while(1) + { + /* 获取一个满位 */ + rt_sem_take(&sem_full, RT_WAITING_FOREVER); + + /* 临界区,上锁进行操作 */ + rt_sem_take(&sem_lock, RT_WAITING_FOREVER); + sum += array[get%MAXSEM]; + rt_kprintf("the consumer[%d] get a number: %d\n", no, array[get%MAXSEM] ); + get++; + rt_sem_release(&sem_lock); + + /* 释放一个空位 */ + rt_sem_release(&sem_empty); + + /* 生产者生产到100个数目,停止,消费者线程相应停止 */ + if (get == 100) break; + + /* 暂停一小会时间 */ + rt_thread_delay(10); + } + + rt_kprintf("the consumer[%d] sum is %d \n ", no, sum); + rt_kprintf("the consumer[%d] exit!\n"); +} + +int producer_consumer_init() +{ + /* 初始化3个信号量 */ + rt_sem_init(&sem_lock , "lock", 1, RT_IPC_FLAG_FIFO); + rt_sem_init(&sem_empty, "empty", MAXSEM, RT_IPC_FLAG_FIFO); + rt_sem_init(&sem_full , "full", 0, RT_IPC_FLAG_FIFO); + + /* 创建线程1 */ + producer_tid = rt_thread_create("producer", + producer_thread_entry, RT_NULL, /* 线程入口是producer_thread_entry, 入口参数是RT_NULL */ + THREAD_STACK_SIZE, THREAD_PRIORITY - 1, THREAD_TIMESLICE); + if (producer_tid != RT_NULL) + rt_thread_startup(producer_tid); + else + tc_stat(TC_STAT_END | TC_STAT_FAILED); + + /* 创建线程2 */ + consumer_tid = rt_thread_create("consumer", + consumer_thread_entry, RT_NULL, /* 线程入口是consumer_thread_entry, 入口参数是RT_NULL */ + THREAD_STACK_SIZE, THREAD_PRIORITY + 1, THREAD_TIMESLICE); + if (consumer_tid != RT_NULL) + rt_thread_startup(consumer_tid); + else + tc_stat(TC_STAT_END | TC_STAT_FAILED); + + return 0; +} + +#ifdef RT_USING_TC +static void _tc_cleanup() +{ + /* 调度器上锁,上锁后,将不再切换到其他线程,仅响应中断 */ + rt_enter_critical(); + + /* 删除线程 */ + if (producer_tid != RT_NULL && producer_tid->stat != RT_THREAD_CLOSE) + rt_thread_delete(producer_tid); + if (consumer_tid != RT_NULL && consumer_tid->stat != RT_THREAD_CLOSE) + rt_thread_delete(consumer_tid); + + /* 调度器解锁 */ + rt_exit_critical(); + + /* 设置TestCase状态 */ + tc_done(TC_STAT_PASSED); +} + +int _tc_producer_consumer() +{ + /* 设置TestCase清理回调函数 */ + tc_cleanup(_tc_cleanup); + producer_consumer_init(); + + /* 返回TestCase运行的最长时间 */ + return 100; +} +/* 输出函数命令到finsh shell中 */ +FINSH_FUNCTION_EXPORT(_tc_producer_consumer, producer and consumer example); +#else +/* 用户应用入口 */ +int rt_application_init() +{ + producer_consumer_init(); + + return 0; +} +#endif