介绍:当开发一个多线程程序时,同步是一个很大的问题。如果你的程序需要数据流包,那么用队列是个好办法。

你可以在 http://www.boost.org/ 发现 boost 库和文档,从它的网站可以看出用boost的优势:

In a word, Productivity. Use of high-quality libraries like Boost speeds initial development, results in fewer bugs, reduces reinvention-of-the-wheel, and cuts long-term maintenance costs. And since Boost libraries tend to become de facto or de jure standards, many programmers are already familiar with them.

下面介绍用boost synchronization class(boost 同步类)来实现。

代码实现:

在例子中,用了线程同步模型来说明producer-consumer(生产者--消费者模型),producer线程创建数据并插入到队列中,consumer线程使用数据并从队列中删除数据。使用了mutex对象来保持两个线程的同步。

用不同的解决方法来实现线程的同步队列,然后比较了它们的优势与不足。

  1. SynchronizedDequeue: is a double-ended queue, implemented with STL deque.
  2. SychronizedVector: is a ring or cycle queue, implemented with STL vector.
  3. SychronizedVectorNB: is the no-blocking version of SychronizedVector.

头文件和接口定义:

Code#include <iostream>
#include <deque>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp> using namespace std; #define default_packesize 1280 class TPacket
{
int my_size;
unsigned char my_databuf[default_packesize];
unsigned int ID;
public:
TPacket() {std::memset(my_databuf,0,sizeof(my_databuf));my_size=0;}
~TPacket() {;}
int GetSize() {return my_size;}
void SetSize(int size) {my_size = size;}
unsigned int GetID() {return ID;}
void SetID(int id) {ID = id;}
bool GetData(char* pbuf,int& size)
{
if(my_size>size)
return false;
size = my_size;
memcpy(pbuf,my_databuf,my_size);
return true;
}
bool SetData(char* pbuf,int size)
{
if(size>default_packesize)
return false;
memcpy(my_databuf,pbuf,size);
my_size=size;
return true;
}
public:
virtual bool IsValid() {return false;}
virtual bool Encode() {return false;}
virtual bool Decode() {return false;}
}; //queue interface
template <class T>
class ISynchronizedQueue
{
public:
virtual bool add(T pkt) = 0;
virtual bool get(T& pkt) = 0;
virtual bool read(T& pkt) = 0;
virtual bool del(T& pkt) = 0;
virtual bool clear() = 0;
};

接口实现:

SynchronizedDequeue有动态的队列大小,好处是如果producer比consumer快,没有数据会丢失,全部的数据将被consumer接收。不足是受内存更大的影响。当要插入队列时分配内存,当consumer线程接收到数据后释放内存。因为会出现内存分配和释放多次,降低了对在同一过程中更大的内存回收。

Codeclass SynchronizedDequeue: public ISynchronizedQueue<TPacket>
{
boost::mutex m_mutex;
deque<TPacket> m_queue;
boost::condition_variable m_cond; public:
bool add(TPacket pkt)
{
boost::lock_guard<boost::mutex> lock(m_mutex);
if(m_queue.size()>100)
m_queue.clear();
m_queue.push_back(pkt);
return true;
}
bool get(TPacket& pkt)
{
boost::lock_guard<boost::mutex> lock(m_mutex);
if (!m_queue.size())
{
return false;
}
pkt = m_queue.front();
m_queue.pop_front();
return true;
} bool read(TPacket& pkt)
{
boost::lock_guard<boost::mutex> lock(m_mutex);
if (!m_queue.size())
{
return false;
}
pkt = m_queue.front();
return true;
} bool del(TPacket& pkt)
{
return get(pkt);
} bool clear()
{
boost::lock_guard<boost::mutex> lock(m_mutex);
m_queue.clear();
return true;
}
};

SychronizedVector使用了固定大小的队列来避免内存开销,但当有新数据来,它会覆盖旧数据,并从队列中刷新出去。

Codeclass SynchronizedVector :public ISynchronizedQueue<TPacket>
{
int queue_size;
boost::mutex m_mutex;
std::vector<TPacket> my_vector;
int start,end; public:
SynchronizedVector(int q_size=100) {queue_size = q_size; start=end=0; my_vector.assign(queue_size,TPacket());}
bool add(TPacket pkt)
{
boost::lock_guard<boost::mutex> lock(m_mutex);
my_vector[end++] = pkt;
if(end>=queue_size)
end = 0;
if(end == start)
start = end+1;
if(start>=queue_size)
start = 0;
return true;
}
bool get(TPacket& pkt)
{
boost::lock_guard<boost::mutex> lock(m_mutex);
if(start==end)
return false;
pkt = my_vector[start++];
if(start>=queue_size)
start = 0;
return true;
}
bool read(TPacket& pkt) //not support
{
return false;
}
bool del(TPacket& pkt) //not support
{
return false;
} bool clear()
{
boost::lock_guard<boost::mutex> lock(m_mutex);
start = end =0;
return true;
}
};

SychronizedVectorNB不会被阻塞,无论是生产者还是消费者线程。优点在于,如果有一些其他activity需要被处理在队列访问线程的过程中,那么non-block将保证响应时间。当线程试图拥有该mutex对象,上述两个队列可以阻塞线程。如果一个线程拥有mutex,那么发生exception时,其他线程也将被阻塞。缺点是,当它不能拥有lock,添加数据到队列时可能失败,那么caller需要再次添加相同的数据。

Codeclass SynchronizedVectorNB :public ISynchronizedQueue<TPacket>
{
int queue_size;
boost::mutex m_mutex;
std::vector<TPacket> my_vector;
int start,end; public:
SynchronizedVectorNB(int q_size=100) {queue_size = q_size; start=end=0; my_vector.assign(queue_size,TPacket());}
bool add(TPacket pkt)
{
boost::unique_lock<boost::mutex> lock(m_mutex,boost::try_to_lock_t());
if(!lock.owns_lock())
return false;
my_vector[end++] = pkt;
if(end>=queue_size)
end = 0;
if(end == start)
start = end+1;
if(start>=queue_size)
start = 0;
return true;
}
bool get(TPacket& pkt)
{
boost::unique_lock<boost::mutex> lock(m_mutex,boost::try_to_lock_t());
if(!lock.owns_lock())
return false; if(start==end)
return false;
pkt = my_vector[start++];
if(start>=queue_size)
start = 0;
return true;
}
bool read(TPacket& pkt) //not support
{
return false;
}
bool del(TPacket& pkt) //not support
{
return false;
} bool clear()
{
boost::lock_guard<boost::mutex> lock(m_mutex);
start = end =0;
return true;
}
};

下面是producer线程代码:

CodeDWORD WINAPI ProducerServerThread(LPVOID lpParam)
{
int count=0; ISynchronizedQueue<TPacket>* pQ = (ISynchronizedQueue<TPacket>*)lpParam;
TPacket pkt;
LOG("\n-------------------------Producer thread begin-----------------------");
while(1)
{
DWORD t1 = GetTickCount();
Sleep(50); if(count++>=1000)
break; //initialize packet data to zero.
memset(&pkt,0,sizeof(pkt)); //add content to packet, I only set the ID here, you can do something more.
pkt.SetID(count); if(pQ->add(pkt))
LOG("Add PACKET ID = %d ",pkt.GetID());
else
LOG("Add Packet Failed");
DWORD t2 = GetTickCount(); LOG("ONE-LOOP DURATION = %d",t2-t1);
}
LOG("\n-------------------------Producer thread end-----------------------");
return 0;
}

下面是consumer线程代码:

CodeDWORD WINAPI ConsumerServerThread(LPVOID lpParam)
{
int count=0;
ISynchronizedQueue<TPacket>* pQ = (ISynchronizedQueue<TPacket>*)lpParam;
TPacket pkt;
LOG("\n-------------------------Cosumer thread begin-----------------------");
while(1)
{
Sleep(10); if(count++>=1200)
break; if(pQ->get(pkt))
LOG("Get Packet ID = %d",pkt.GetID());
else
LOG("Get Packet Failed");
}
LOG("\n-------------------------Cosumer thread end-----------------------");
return 0;
}

下面是main线程代码:

CodeSynchronizedDequeue m_q[5];
//SynchronizedVector m_q[5];
//SynchronizedVectorNB m_q[5] int _tmain(int argc, _TCHAR* argv[])
{
int thread_count =5;
HANDLE server_threads[10]; for (int i=0; i < thread_count ;i++)
{
server_threads[i] = CreateThread(
NULL,
0,
ProducerServerThread,
&m_q[i],
0,
NULL
);
if (server_threads[i] == NULL)
{
LOG( "Create Thread failed: %d\n", GetLastError());
return 0;
}
} for (int i= 0; i < thread_count ;i++)
{
server_threads[i+thread_count] = CreateThread(
NULL,
0,
ConsumerServerThread,
&m_q[i],
0,
NULL
);
if (server_threads[i] == NULL)
{
LOG( "Create Thread failed: %d\n", GetLastError());
return 0;
}
} // Wait until the threads exit, then cleanup
int retval = WaitForMultipleObjects(
2*thread_count,
server_threads,
TRUE,
INFINITE
);
if ((retval == WAIT_FAILED) || (retval == WAIT_TIMEOUT))
{
LOG( "WaitForMultipleObjects failed: %d\n", GetLastError());
return 0;
}
}

在测试代码中,创建了五个producers,五个consumers和五个队列。每个producer都有其伙伴consumer通过使用相同的队列链接。可以验证,如果创建的每个数据包的数据,都是consumer线程通过它的数据包ID处理的。

原英文链接:http://www.codeproject.com/Articles/442452/Thread-Synchronization-Queue-with-Boost

Thread Synchronization Queue with Boost的更多相关文章

  1. 【Python@Thread】queue模块-生产者消费者问题

    python通过queue模块来提供线程间的通信机制,从而可以让线程分项数据. 个人感觉queue就是管程的概念 一个生产者消费者问题 from random import randint from ...

  2. .NET:CLR via C# Primitive Thread Synchronization Constructs

    User-Mode Constructs The CLR guarantees that reads and writes to variables of the following data typ ...

  3. Thread Based Parallelism - Thread Synchronization With Lock

    Thread Based Parallelism - Thread Synchronization With Lock import threading shared_resource_with_lo ...

  4. Thread Based Parallelism - Thread Synchronization With a Condition

    Thread Based Parallelism - Thread Synchronization With a Condition from threading import Thread, Con ...

  5. Synchronization in Delphi TThread class : Synchronize, Queue

    http://embarcadero.newsgroups.archived.at/public.delphi.rtl/201112/1112035763.html > Hi,>> ...

  6. boost::lockfree::queue多线程读写实例

    最近的任务是写一个多线程的东西,就得接触多线程队列了,我反正是没学过分布式的,代码全凭感觉写出来的,不过运气好,代码能够work= = 话不多说,直接给代码吧,一个多消费者,多生产者的模式.假设我的任 ...

  7. 【转】Native Thread for Win32 B-Threads Synchronization(通俗易懂,非常好)

    http://www.bogotobogo.com/cplusplus/multithreading_win32B.php   Synchronization Between Threads In t ...

  8. 使用boost实现线程池thread pool | boost thread pool example

    本文首发于个人博客https://kezunlin.me/post/f241bd30/,欢迎阅读! boost thread pool example Guide boost thread pool ...

  9. boost之thread

    1.boost里的thread创建之后会立即启动. 代码示例: #include <iostream> #include <string> #include <vecto ...

随机推荐

  1. ASP.NET Web API 2 媒体类型格式化程序

    Ø  简介 在之前的ASP.NET Web API 2 消息处理管道文章中有提到,在 Web API 的生命周期中,还包含比较中要的一部分,就是媒体类型格式化程序,该程序主要用于处理 Web API ...

  2. 12.scrapy框架

    一.Scrapy 框架简介 1.简介 Scrapy是用纯Python实现一个为了爬取网站数据.提取结构性数据而编写的应用框架,用途非常广泛. 框架的力量,用户只需要定制开发几个模块就可以轻松的实现一个 ...

  3. tensorflow---alexnet training (tflearn)

    # 输入数据 import input_data mnist = input_data.read_data_sets("/tmp/data/", one_hot=True) imp ...

  4. SQL Server 远程备份详解

    例1: 有A数据库服务器,B本机: 我现在想通过在B机器上通过代码调用SQL来执行A数据库的备份到B机器上 调用的SQL语句为:Backup Database MYDATABASE To Disk=' ...

  5. 数据库设计理论与实践·<四>数据库基本术语及其概念

    一.关系模型 关系模型是最重要的一种数据模型.关系数据库模型系统采用关系模型作为数据的组织方式. 关系模型的数据结构: 关系:一张表 元组:一行记录. 属性:一列 [码(键,key)]:表中的某个属性 ...

  6. c语言 弹弹球小游戏

    #include <stdio.h>#include <stdlib.h>#include <windows.h>#include <time.h>#i ...

  7. 5-8套接字socket

    socket概念 socket层 理解socket Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协 ...

  8. 4-24日 collections模块 random模块 time模块 sys模块 os模块

    1, collections模块 在内置数据类型(dict.list.set.tuple)的基础上,collections模块还提供了几个额外的数据类型:Counter.deque.defaultdi ...

  9. MySql 在cmd下的学习笔记 —— 有关储存过程的操作(procedure)

    我们把若干条sql封装取来,起个名字------把此过程存储在数据库中叫存储过程 调用procedure 储存过程是可以变成的,意味着可以使用变量,表达式,控制结构 来完成复杂的功能 声明变量 pro ...

  10. Nginx系列2:用Nginx搭建一个可用的静态资源Web服务器

    上一节中编译好自己的nginx服务器后, 现在要对nginx.conf文件进行配置,搭建一个可用的静态资源Web服务器 1.放入可访问的html文件到nginx文件夹下,如图1所示: 这里我放入的是一 ...