246 lines
5.4 KiB
C++
246 lines
5.4 KiB
C++
/************************************************************************
|
|
*
|
|
* Copyright (c) 2017 Alibaba.com, Inc. All Rights Reserved
|
|
* $Id: single_process_queue.h,v 1.0 01/11/2017 10:17:19 AM yingqiang.zyq(yingqiang.zyq@alibaba-inc.com) $
|
|
*
|
|
************************************************************************/
|
|
|
|
/**
|
|
* @file single_process_queue.h
|
|
* @author yingqiang.zyq(yingqiang.zyq@alibaba-inc.com)
|
|
* @date 01/11/2017 10:17:19 AM
|
|
* @version 1.0
|
|
* @brief
|
|
*
|
|
**/
|
|
|
|
#ifndef single_process_queue_INC
|
|
#define single_process_queue_INC
|
|
|
|
#include <atomic>
|
|
#include <queue>
|
|
#include <mutex>
|
|
|
|
|
|
namespace alisql {
|
|
|
|
/**
|
|
* @class SingleProcessQueue
|
|
*
|
|
* @brief
|
|
*
|
|
**/
|
|
template<typename TaskType>
|
|
class SingleProcessQueue {
|
|
public:
|
|
SingleProcessQueue () :stop_(false) {onProcess_.store(false);}
|
|
virtual ~SingleProcessQueue () {};
|
|
bool push(TaskType *task) {
|
|
std::lock_guard<std::mutex> lg(lock_);
|
|
if (!stop_)
|
|
{
|
|
taskList_.push(task);
|
|
return !onProcess_.load();
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
void start() {
|
|
std::lock_guard<std::mutex> lg(lock_);
|
|
stop_= false;
|
|
}
|
|
/* true: the caller should delete queue. */
|
|
bool stop(bool wait= false) {
|
|
bool ret= true;
|
|
lock_.lock();
|
|
stop_= true;
|
|
while (!taskList_.empty())
|
|
{
|
|
TaskType *task= taskList_.front();
|
|
taskList_.pop();
|
|
delete task;
|
|
}
|
|
if (!wait && onProcess_.load())
|
|
{
|
|
taskList_.push(NULL);
|
|
ret= false;
|
|
}
|
|
lock_.unlock();
|
|
if (wait)
|
|
while (onProcess_.load()) ;
|
|
return ret;
|
|
}
|
|
void process(std::function<void(TaskType*)> cb) {
|
|
uint64_t tasks;
|
|
lock_.lock();
|
|
if (onProcess_.load() || stop_)
|
|
{
|
|
lock_.unlock();
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
onProcess_.store(true);
|
|
lock_.unlock();
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
lock_.lock();
|
|
tasks= taskList_.size();
|
|
if (tasks == 0)
|
|
{
|
|
onProcess_.store(false);
|
|
lock_.unlock();
|
|
break;
|
|
}
|
|
TaskType *task= taskList_.front();
|
|
taskList_.pop();
|
|
lock_.unlock();
|
|
|
|
if (task == NULL)
|
|
return;
|
|
cb(task);
|
|
delete task;
|
|
}
|
|
}
|
|
void mergeableProcess(std::function<void(TaskType*)> cb) {
|
|
uint64_t tasks;
|
|
lock_.lock();
|
|
if (onProcess_.load() || stop_)
|
|
{
|
|
lock_.unlock();
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
onProcess_.store(true);
|
|
lock_.unlock();
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
uint64_t mergedTaskNum= 1;
|
|
lock_.lock();
|
|
tasks= taskList_.size();
|
|
if (tasks == 0)
|
|
{
|
|
onProcess_.store(false);
|
|
lock_.unlock();
|
|
break;
|
|
}
|
|
TaskType *task= taskList_.front();
|
|
taskList_.pop();
|
|
while (taskList_.size() >= 1)
|
|
{
|
|
TaskType *nextTask= taskList_.front();
|
|
if (nextTask == NULL)
|
|
{
|
|
delete task;
|
|
task= NULL;
|
|
break;
|
|
}
|
|
if (task->merge(nextTask))
|
|
{
|
|
++ mergedTaskNum;
|
|
taskList_.pop();
|
|
delete nextTask;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
lock_.unlock();
|
|
if (task == NULL)
|
|
return;
|
|
|
|
if (mergedTaskNum >= 2)
|
|
task->printMergeInfo(mergedTaskNum);
|
|
cb(task);
|
|
delete task;
|
|
}
|
|
}
|
|
|
|
static void mergeableProcessWeak(std::weak_ptr<SingleProcessQueue<TaskType>> wqueue, std::function<void(TaskType*)> cb)
|
|
{
|
|
// skip the async call if object has been deleted
|
|
if (auto q = wqueue.lock())
|
|
q->mergeableProcess(cb);
|
|
}
|
|
|
|
void mergeableSameProcess(std::function<void(TaskType*)> cb) {
|
|
uint64_t tasks;
|
|
lock_.lock();
|
|
if (onProcess_.load() || stop_)
|
|
{
|
|
lock_.unlock();
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
onProcess_.store(true);
|
|
lock_.unlock();
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
uint64_t mergedTaskNum= 1;
|
|
lock_.lock();
|
|
tasks= taskList_.size();
|
|
if (tasks == 0)
|
|
{
|
|
onProcess_.store(false);
|
|
lock_.unlock();
|
|
break;
|
|
}
|
|
TaskType *task= taskList_.front();
|
|
taskList_.pop();
|
|
while (taskList_.size() >= 1)
|
|
{
|
|
TaskType *nextTask= taskList_.front();
|
|
if (nextTask == NULL)
|
|
{
|
|
delete task;
|
|
task= NULL;
|
|
break;
|
|
}
|
|
++ mergedTaskNum;
|
|
taskList_.pop();
|
|
delete nextTask;
|
|
}
|
|
lock_.unlock();
|
|
if (task == NULL)
|
|
return;
|
|
|
|
cb(task);
|
|
if (mergedTaskNum > 100)
|
|
msleep_(2);
|
|
delete task;
|
|
}
|
|
}
|
|
|
|
protected:
|
|
void msleep_(uint64_t t)
|
|
{
|
|
struct timeval sleeptime;
|
|
if (t == 0)
|
|
return;
|
|
sleeptime.tv_sec= t / 1000;
|
|
sleeptime.tv_usec= (t - (sleeptime.tv_sec * 1000)) * 1000;
|
|
select(0, 0, 0, 0, &sleeptime);
|
|
}
|
|
|
|
protected:
|
|
std::queue<TaskType *> taskList_;
|
|
std::mutex lock_;
|
|
std::atomic<bool> onProcess_;
|
|
bool stop_;
|
|
|
|
private:
|
|
SingleProcessQueue ( const SingleProcessQueue &other ); // copy constructor
|
|
const SingleProcessQueue& operator = ( const SingleProcessQueue &other ); // assignment operator
|
|
|
|
};/* end of class SingleProcessQueue */
|
|
} //namespace alisql
|
|
|
|
#endif //#ifndef single_process_queue_INC
|