概述
本次工程使用Plugin插件实现实现生产者消费者模型,创建两个线程,分别用于生产、购买;产品数量的上限为6;两个线程分别对其进行设置,当数量达到上限6时,生产者暂停生产,等待消费者购买;当数量达到下限0时,消费者暂停购买,等待生产者生产。
效果
创建属性
这里我们创建4个属性分别用于存放数量、显示文字
SSR_PLUGIN_PROPERTY("Thread", "BufferSize", TYPE_INT, "6", 0, 6, "BufferSize", PCT_TextBoxBind) //产品数量
SSR_PLUGIN_PROPERTY("Sum", "ProducerSum", TYPE_INT, " 0", 0, 65535, "ProducerSum", PCT_TextBoxBind) //生产总量
SSR_PLUGIN_PROPERTY("Sum", "ConsumerSum", TYPE_INT, " 0",0 , 65535, "ConsumerSum", PCT_TextBoxBind) //购买总量
SSR_PLUGIN_PROPERTY("Text", "Text", TYPE_INT, " ", , , "Text", PCT_TextBox) //存放文字,显示当前操作
int product_quantity = 0; // 当前库存容量
int BUFFER_SIZE = 6; // 最大数量
int P_Sum = 0, C_Sum = 0; // 计算生产/消费总数量
//接收返回值,用作判断:线程是否创建成功
int ret_p;
int ret_c;
pthread_t producer_thread; //生产者ID
pthread_t consumer_thread; //消费者ID
pthread_mutex_t mutex; //互斥锁
pthread_cond_t producer_cond; //生产者条件变量
pthread_cond_t consumer_cond; //消费者条件变量
创建线程
这里我们创建2个线程,分别是Producer(生产者)、Consumer(消费者),并对其设置具体操作。
- 消费者、生产者 不能同时拥有锁(mutex),当生产者对资源(product_quantity)进行访问设置时,生产者拥有锁,其余线程等待生产者设置完成后通知或等待解锁。
- 当数量达到上限6时,生产者暂停生产,等待消费者购买;当数量达到下限0时,消费者暂停购买,等待生产者生产
- 每次线程执行时,向Text属性输出当前操作(购买/生产 1个),ProducerSum、ConsumerSum输出生产/购买总数。
- 通过sleep控制间隔时间
SSRObject* UserPluginDLL::createSSRObject()
{
#ifdef TYPE_PLUGIN_DATA
SSRObject* ssrObj = new UserPluginDLL;
#else
SSRObject* ssrObj = new SSRObject;
#endif
ssrObj->m_ssRptr_plugin = this;
ssrObj->m_ssRtype = OBJECT_TYPE_PLUGIN;
pthread_mutex_init(&mutex, NULL); //初始化
ret_p = pthread_create(&producer_thread, NULL, Producer, (void *)ssrObj);// 创建生产者线程
if (ret_p != 0) {
Common::printlog(LOG_LEV_ERROR, "Error____Producer! \n");
}
ret_c = pthread_create(&consumer_thread, NULL, Consumer, (void *)ssrObj);// 创建消费者线程
if (ret_c != 0) {
Common::printlog(LOG_LEV_ERROR, "Error____Consumer! \n");
}
return ssrObj;
}
SSR_PLUGIN_DEFINITION(UserPluginDLL)//调用此宏定义,创建预定义函数接口
void* Producer(void* arg)
{
SSRObject* ssrObject = (SSRObject*)arg;
//int count = 0;//ssTools::Common::int2str(count);
UserPluginDLL* dataSource = (UserPluginDLL*)ssrObject->m_ssRptr_plugin;
while (1) {
pthread_mutex_lock(&dataSource->mutex); // 加锁
// 如果库存已满,等待购买
while (dataSource->product_quantity >= dataSource->BUFFER_SIZE) {
Common::printlog(LOG_LEV_ERROR, "Wait_____Consumer……\n");
pthread_cond_wait(&dataSource->producer_cond, &dataSource->mutex);
pthread_mutex_unlock(&dataSource->mutex);// 解锁
Sleep(1500);
}
Common::printlog(LOG_LEV_ERROR, "当前数量:%d\n", dataSource->product_quantity);
// 生产商品
dataSource->product_quantity++;
dataSource->P_Sum++;
Common::printlog(LOG_LEV_ERROR, "生产1个\n");
dataSource->m_renderEngine->getPropertySystem()->setPropertyValue(ssrObject, "ProducerSum", Common::int2str(dataSource->P_Sum));
dataSource->m_renderEngine->getPropertySystem()->setPropertyValue(ssrObject, "BufferSize", Common::int2str(dataSource->product_quantity));
dataSource->m_renderEngine->getPropertySystem()->setPropertyValue(ssrObject, "Text", "生产1个");
pthread_mutex_unlock(&dataSource->mutex);// 解锁
pthread_cond_signal(&dataSource->consumer_cond);// 发送信号,唤醒等待的线程
Sleep(2000);
}
return ssrObject;
}
void* Consumer(void* arg)
{
SSRObject* ssrObject = (SSRObject*)arg;
UserPluginDLL* dataSource = (UserPluginDLL*)ssrObject->m_ssRptr_plugin;
while (1) {
pthread_mutex_lock(&dataSource->mutex); // 加锁
// 如果库存为空,等待生产
while (dataSource->product_quantity <= 0) {
Common::printlog(LOG_LEV_ERROR, "Wait_____Producer————\n");
pthread_cond_wait(&dataSource->consumer_cond, &dataSource->mutex);
pthread_mutex_unlock(&dataSource->mutex);// 解锁
Sleep(1000);
}
Common::printlog(LOG_LEV_ERROR, "当前数量:%d\n", dataSource->product_quantity);
// 购买商品
dataSource->product_quantity--;
Common::printlog(LOG_LEV_ERROR, "购买1个\n");
dataSource->C_Sum++;
dataSource->m_renderEngine->getPropertySystem()->setPropertyValue(ssrObject, "ConsumerSum", Common::int2str(dataSource->C_Sum));
dataSource->m_renderEngine->getPropertySystem()->setPropertyValue(ssrObject, "BufferSize", Common::int2str(dataSource->product_quantity));
dataSource->m_renderEngine->getPropertySystem()->setPropertyValue(ssrObject, "Text", "购买1个");
pthread_mutex_unlock(&dataSource->mutex);// 解锁
pthread_cond_signal(&dataSource->producer_cond);// 发送信号,唤醒等待的线程
Sleep(2500);
}
return ssrObject;
}
编译
此时我们编译完成,鼠标右键弹出菜单,点击生成,找到我们生成后的文件路径
使用Plugin
1.打开ssRenderEditor,Resource窗口中点击New Plugin,选择刚才生成后的Plugin路径。
2.拖拽Plugin到Page节点下
3.创建4个Text节点设置Text属性绑定,用于显示Plugin的属性。
小结:
制作工程时用时比较长的是理解线程的实现和一些接口的使用方法,需要注意的是使用pthread_cond_wait时最好用while循环判断,因为如果用if会出现虚假唤醒的情况:当信号中断时也会去唤醒它。