RT-Thread: Design pattern of the Producer-consumer model (Semaphore)

本文介绍RT-Thread实时操作系统中的信号量使用方法及其实现的生产者消费者模式。通过示例代码展示了如何创建、使用及删除信号量,并实现了一个简单的生产者消费者模型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Lower layer APIs concerning to RT-Thread can be found on 

http://www.rt-thread.org/phpBB3/


1. General description:

        RT-Thread is an open source real-time operating system for embedded devices from China, which has strong scalability: from a tiny kernel runnning on a tiny core, for example ARM Cortex-M, or Cortex-M3/4/7, to a rich feature system running on ARM Cortex-A8, ARM Cortex-A9 DualCore etc.

The producer/consumer design pattern is based on the master/Slave design pattern which used to decouple processes that produce data., and those that consume the data produced. Data queues are used to communicate data between loops in the Producer/Consumer design pattern. These queues offer the advantage of data buffering between producer and consumer loops.

The model is commonly used when acquiring multiple sets of data to be processed in order. Suppose you want to write an application that accepts data while processing them in the order they were received. Because queuing up this data is much faster than the actual processing, the Producer/Consumer design pattern is best suited for this application. We could conceivably put both the producer and consumer in the same loop for this application, but the processing queue will not be able to add any additional data until the first piece of data is done processing. The producer/consumer pattern approach to this application would be to queue the data in the producer loop, and have the actual processing done in the consumer loop. This in effect will allow the consumer loop to process the data at its own pace, while allowing the producer loop to queue additional data at the same time.

semaphore is a lightweight kernel object that solves the problem of thread synchronization. Threads can acquire or release it to achieve the purpose of synchronization or mutual exclusion. The semaphore is like a key that locks a critical area and allows only a key thread to be accessed: the thread gets the key before it is allowed to enter the critical area; after leaving the key is passed to the queue wait for the thread, so that follow-up thread into the critical area in turn.

2. APIs description:

   I'll provide some APIs concerning to semaphore here.

1) Create the semaphore, the kernel firstly creates a semaphore controlling module, then do the initialization work.

    2) Delete the semaphore. Once delete it when a thread is waiting for it, the delete operation will awake the thread on the semaphore. And the return value to the thread is RT_ERROR.

 

3) Detach the semaphore, move away the object of the semaphore from the kernel.

4) Provide the thread to achieve semaphore resources. When the semaphore is over than zero, the thread

will achieve the semaphore.

5) Release the semaphore, when the thread has completely visited the resources, release the semaphore as soon as possible.


3. Test and Codes:

/*
 * File      : application.c
 * This file is part of RT-Thread RTOS
 * COPYRIGHT (C) 2006, RT-Thread Development Team
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
 * http://www.rt-thread.org/license/LICENSE
 *
 * Change Logs:
 * Date           Author       Notes
 * 2017-02-11     Kyrie      the first version
 * 2014-02-15     Kyrie      make code cleanup. 
 */

#include <board.h>
#include <rtthread.h>
#include <dfs_posix.h>
//#include "tc_comm.h"//debugging interface
#ifdef RT_USING_GDB
#include <gdb_stub.h>
#endif

//#include <sha1.h>
/*************zzh******************+*/
#define MAXSEM 5

#define THREAD_PRIORITY 25
#define THREAD_STACK_SIZE 512
#define THREAD_TIMESLICE 5
rt_uint32_t array[MAXSEM];
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;
/*************zzh******************-*/
extern void rt_hw_led_set_on(rt_uint8_t led);
extern void rt_hw_led_set_off(rt_uint8_t led);
/*************zzh******************+*/
//static rt_thread_t tid = RT_NULL, tid2 = RT_NULL;
static rt_sem_t sem = RT_NULL;//sem struct
static rt_thread_t tid = RT_NULL;

/*************zzh******************-*/
#define MASTER_KEY  "electrical lift controller"

/*************zzh******************+*/
/*static struct rt_thread thread1;
ALIGN(4)
static rt_uint8_t thread1_stack[THREAD_STACK_SIZE];
static struct rt_thread thread2;
ALIGN(4)
static rt_uint8_t thread2_stack[THREAD_STACK_SIZE];*/
/*************zzh******************-*/
//static rt_thread_t tid = RT_NULL;
//static rt_thread_t tid2 = RT_NULL;
//static rt_uint32_t cnt;
static rt_uint32_t test=0;
void rt_init_thread_entry2(void* parameter)
{
	rt_uint32_t count = 0;
	rt_uint32_t no = (rt_uint32_t) parameter;
	while(1)
	{
		rt_kprintf("thread%d count: %d\n", no, count ++);
		//rt_thread_delay(10);
		//rt_thread_yield();
	}
}

static void rt_init_thread_entry(void* parameter)
{
//#ifdef RT_USING_COMPONENTS_INIT
    /* RT-Thread components initialization */
//    rt_components_init();
//#endif

//	rt_kprintf("Hello RT-Thread !!!\n");
		
	
			/*************zzh******************+*/
			//create a thread
	//rt_uint32_t count = 0;
	//rt_uint32_t no = (rt_uint32_t) parameter;
	//		rt_uint32_t no;
//	no = (rt_uint32_t) parameter;
	
	rt_err_t result;
	rt_tick_t tick;
	
	tick = rt_tick_get();
	
	result = rt_sem_take(sem, 10);
	
	if (result == -RT_ETIMEOUT)
	{
		if(rt_tick_get()-tick!=10)
		{
			rt_sem_delete(sem);
			return;
		}
		rt_kprintf("take semaphore timeout\n");
	}
	else
	{
			rt_sem_delete(sem);
			return;
	}
	
			rt_sem_release(sem);
	
			result = rt_sem_take(sem, RT_WAITING_FOREVER);
	
	if (result != RT_EOK)
	{

			rt_sem_delete(sem);
			return;

	}
	
	rt_sem_delete(sem);
	/*********zzh******************-*/
			

	/* SHA-1 test */
/*	{
	    sha1_context ctx;
	    rt_uint8_t output[20];
	    rt_uint8_t input[4] = {0x30,0x31,0x32,0x33};
        rt_uint8_t usr_sn[16];
*/
        /* generate usr_key */
	/*    sha1_hmac_reset(&ctx);
	    sha1_hmac_starts(&ct x,MASTER_KEY,rt_strlen(MASTER_KEY));
	    sha1_hmac_update(&ctx,input,4);
	    sha1_hmac_finish(&ctx,output);
        rt_memcpy(usr_sn,&output[4],16);
*/
        /* SEC0 KEYA */
    /*    sha1_hmac_reset(&ctx);
        sha1_hmac_starts(&ctx,usr_sn,16);
        sha1_hmac_update(&ctx,"SEC0KEYA",8);
        sha1_hmac_finish(&ctx,output);
        rt_kprintf("SHA1-HMAC SEC0 KEYA end...\n");
*/
        /* SEC0 KEYB */

     /*   sha1_hmac_reset(&ctx);
        sha1_hmac_starts(&ctx,usr_sn,16);
        sha1_hmac_update(&ctx,"SEC0KEYB",8);
        sha1_hmac_finish(&ctx,output);
        rt_kprintf("SHA1-HMAC SEC0 KEYA end...\n");
	}*/


	while(1)
	{
		static rt_uint8_t tickCount = 0;

		rt_hw_led_set_on(tickCount);
		rt_hw_led_set_off(~tickCount);
		rt_thread_delay(RT_TICK_PER_SECOND);

		tickCount++;
	}

}


int semaphore_dynamic_init()
{
	sem = rt_sem_create("sem", 0, RT_IPC_FLAG_FIFO);
	if(sem== RT_NULL)
	{
		//tc_stat(TC_STAT_END | TC_STAT_FAILED);
		return 0;
	}
	
	tid = rt_thread_create("thread",
        rt_init_thread_entry,(void*)0,
					THREAD_STACK_SIZE,
				THREAD_PRIORITY,
				THREAD_TIMESLICE);
		if(tid != RT_NULL)
		rt_thread_startup(tid);
	
	return 0;
}



void consumer_thread_entry(void* parameter)
{
	rt_uint32_t no;
	rt_uint32_t sum = 0;
		
	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);
		
		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");
}

void producer_thread_entry(void* parameter)
{
	
	rt_int32_t cnt = 0;
	while(cnt <= 100)
	{
		rt_sem_take(&sem_empty, RT_WAITING_FOREVER);
		
		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(10);		
	}
		rt_kprintf("the producer exit!\n");
}



int semaphore_producer_consumer_init()
{
	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);
	
	producer_tid = rt_thread_create("producer",
	producer_thread_entry, 
	RT_NULL, 
	THREAD_STACK_SIZE, THREAD_PRIORITY - 1, THREAD_TIMESLICE);
	if (producer_tid != RT_NULL)
	rt_thread_startup(producer_tid);
	
	consumer_tid = rt_thread_create("consumer",
	consumer_thread_entry,
	RT_NULL, 
	THREAD_STACK_SIZE, THREAD_PRIORITY + 1, THREAD_TIMESLICE);
	if (consumer_tid != RT_NULL)
	rt_thread_startup(consumer_tid);
	
	return 0;
}

int rt_application_init()
{
    //semaphore_dynamic_init();
		semaphore_producer_consumer_init();
	 /* rt_thread_t tid;
    tid = rt_thread_create("t1",
        rt_init_thread_entry,(void*)10,
        2048, 10, 5);
		
    if (tid != RT_NULL)
        rt_thread_startup(tid);*/

		/*************zzh******************+*/
		//rt_thread_t tid2;
		/*tid = rt_thread_create("t2",
		      rt_init_thread_entry,(void*)20,
					2048,20,5);
					
		if (tid != RT_NULL)
        rt_thread_startup(tid);*/
		/*************zzh******************-*/
	/*************zzh******************+*/
	/*	rt_err_t result;
		result = rt_thread_init(&thread1, "t1", 
			rt_init_thread_entry, (void*)1, 
			&thread1_stack[0], sizeof(thread1_stack), 
			THREAD_PRIORITY, 10);
		if (result == RT_EOK) 
			rt_thread_startup(&thread1);
		else
		return -1;
		
		result = rt_thread_init(&thread1, "t2", 
			rt_init_thread_entry, (void*)2, 
			&thread1_stack[0], sizeof(thread2_stack), 
			THREAD_PRIORITY+1, 10);
		if (result == RT_EOK) 
			rt_thread_startup(&thread2);
		else
		return -1;*/
		/*************zzh******************-*/
    return 0;
}

/*@}*/

Author: Kyrie



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值