c++实现半同步半异步I/O的设计模式(half sync/half async)

半同步半异步I/O的设计模式(half sync/half async)


1.动机:

众所周知,同步模式编程简单,但是I/O的利用利率低;而异步模式编程复杂,但是I/O利用率高。
综合同步异步的有优点,就有了半同步半异步的设计模式。

这个模式中,高层使用同步I/O模型,简化编程。低层使用异步I/O模型,高效执行。

half sync/half async可以很好的使得"变成复杂度"和"执行效率"之间达到一种平衡.


2.应用场景:

半同步半异步模式在下面的场景中使用:

2.1 一个系统中的进程有下面的特征:

系统必须响应和处理外部异步发生的事件,
如果为每一个外部资源的事件分派一个独立的线程同步处理I/O,效率很低。
如果上层的任务以同步方式处理I/O,实现起来简单。

2.2 一个或多个任务必须在单独的控制线程中执行,其它任务可以在多线程中执行:

上层的任务(如:数据库查询,文件传输)使用同步I/O模型,简化了编写并行程序的难度。
而底层的任务(如网络控制器的中断处理)使用异步I/O模型,提供了执行效率。

一般情况下,上层的任务要比下层的任务多,使用一个简单的层次实现异步处理的复杂性,可以对外隐藏异步处理的细节。另外,同步层次和异步层次任务间的通信使用一个队列来协调。


3.实现方案:

可以分为三层:同步任务层,队列层,异步任务层。

3.1 同步任务层(用户级的进程):

本层的任务完成上层的I/O操作,使用同步I/O模型,通过队列层的队列中传输数据。和异步层不同,同步层的任务使用活动对象执行,这些活动对象有自己运行栈和寄存器状态。当执行同步I/O的时候,他们会被阻塞/睡眠。

3.2 队列层:

这个层在同步任务层和异步任务层之间,提供了同步控制和缓存的功能。异步任务的I/O 事件被缓存到消息队列中,同步任务层在队列中提取这些事件(相反方向亦然)

3.3 异步任务层:

处理低层的事件,这些事件由多个外部的事件源产生(例如网卡,终端)。和异步任务不同,此层的实体是被动对象,没有自己的运行栈,要求不能被阻塞。


4.优缺点:

4.1 半同步半异步模式有下面的优点:

上层的任务被简化
不同层可以使用不同的同步策略
层间的通信被限制在单独的一点,因为所有的交互使用队列层协调。
在多处理器环境中提高了性能。

4.2 半同步半异步模式有下面的缺点:

跨边界导致的性能消耗,这是因为同步控制,数据拷贝和上下文切换会过度地消耗资源。

上层任务缺少异步I/O的实现。

编程实例:
#include 
#include 
#include 
#include 
// for file operation.  
#include   
#include   
#include   
#include 
#include 
#include 
#include 
using namespace std;

//队列层
class TaskQueue
{
public:
    struct TaskItem
	{
		char* buffer;
		int startoffset;
		int size;

		TaskItem& operator=(const TaskItem& item)
		{
			if(this == &item)
				return *this;
			buffer = item.buffer;
			size = item.size;
			startoffset = item.startoffset;
			return *this;	
		}
	};
    TaskQueue():refstart(0),refend(0)
	{
		pthread_mutex_init(&mutex, NULL);
		pthread_cond_init(&cond, NULL);
	}
    virtual ~TaskQueue()
	{
		pthread_mutex_lock(&mutex);
		pthread_cond_signal(&cond);
		pthread_mutex_unlock(&mutex);
		
		pthread_mutex_destroy(&mutex);
		pthread_cond_destroy(&cond);

		if(getSize()>0)
		{
			vector::iterator iter = m_items.begin();
			for(;iter != m_items.end(); ++iter)
			{
				if((*iter)->buffer != NULL)
					delete (*iter)->buffer;
				delete (*iter);
			}
		}
	}

	void push(TaskItem *item)
	{
		pthread_mutex_lock(&mutex);
		m_items.push_back(item);
		++refend;
		if(refend > refstart)
		{
			pthread_cond_signal(&cond);
		}
		pthread_mutex_unlock(&mutex);
	}
	TaskItem* pop()
	{
		pthread_mutex_lock(&mutex);
		if(m_items.empty() || refstart > refend)
		{
            pthread_cond_wait(&cond, &mutex);
		}
        TaskItem* item = m_items[refstart++];
		pthread_mutex_unlock(&mutex);
        return item;
	}
	int getSize()
	{
		pthread_mutex_lock(&mutex);
		int size = m_items.size();
		pthread_mutex_unlock(&mutex);
		return size;
	}

	void print()
	{
		if(!m_items.empty())
		{
			vector::iterator iter = m_items.begin();
			for(;iter != m_items.end(); ++iter)
			{
				cout << (*iter)->buffer<< endl;
			}
		}
	}
private:
	vector m_items;
	pthread_cond_t cond;
	pthread_mutex_t mutex;
	int refstart;
	int refend;
};
//异步任务层
class AioProcessor
{
public:
	AioProcessor(int fd, TaskQueue* queue):m_fd(fd), m_queue(queue)
	{
		isRun = false;
	    req.tv_sec = 0;
		req.tv_nsec = 1000*1000*1000;
	}
	~AioProcessor()
	{
		isRun = false;
		vector::iterator iter = m_tids.begin();
		for(;iter !=m_tids.end(); ++iter)
		{
			pthread_join(*iter, NULL);
		}
	}
	void startUP(int count)
	{
		isRun = true;
		for(int i=0;i(process), this);
			m_tids.push_back(tid);
		}

	}
	static void* process(void* arg)
	{
		AioProcessor *proc = (AioProcessor*)arg;
		TaskQueue::TaskItem *item;
		while(proc->isRun)
		{
			if((item = proc->m_queue->pop()) != NULL)
			{
				if(pread(proc->m_fd, item->buffer, item->size, item->startoffset) < 0)
				{
					cout << "read err\n";
					break;
				}
			}
			else
			{
				while(nanosleep(&(proc->req), &(proc->rem))!=0)
				{
					if(errno == EINTR)
					{
						proc->req = proc->rem;
					}
					else
						break;
				}
			}
		}
	}

private:
	TaskQueue *m_queue;
	vector m_tids;
	int m_fd;
	struct timespec req, rem;
	bool isRun;
};
//应用层
class AppExcutor
{
public:
    AppExcutor(int fd):m_fd(fd), queue() 
	{
		proc = new AioProcessor(fd, &queue);
		proc->startUP(3);		
	}
    virtual ~AppExcutor()
	{
		if(proc)
		{
		    delete proc;
			proc = NULL;
		}
	}
	void reader(const int startoffset, int size, char* buf)
	{
		item = new TaskQueue::TaskItem();
		item->buffer = buf;
		item->size = size;
		item->startoffset = startoffset;
		queue.push(item);        
	}

	void print()
	{
		queue.print();
	}
private:
	TaskQueue queue;
	AioProcessor *proc;
	int m_fd;
	TaskQueue::TaskItem *item;
};

int main(int argc, char *argv[])
{
    int fd = open("./testfile", O_RDONLY);
	if(fd < 0)
		return -1;
	AppExcutor excutor(fd);
	int size = 50;
	for(int i=0;i<10; ++i)
	{
		char *buf = new char[size+1];
		memset(buf, 0, sizeof(buf));
		excutor.reader(i*size, size, buf);
	}
	excutor.print();
    return 0;
}

参考文章:http://www.linuxidc.com/Linux/2015-01/112507p7.htm

你可能感兴趣的:(c/c++,算法/数据结构)