c++千万数据级别正确使用无锁队列,避免内存撕碎
Posted qianbo_insist
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++千万数据级别正确使用无锁队列,避免内存撕碎相关的知识,希望对你有一定的参考价值。
1、 内存
2、时间计算类
这个时间计算在我以前的文章里面都有
class TicToc
public:
TicToc()
tic();
void tic()
start = std::chrono::system_clock::now();
double toc()
end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end - start;
start = end;
return elapsed_seconds.count() * 1000;
private:
std::chrono::time_point<std::chrono::system_clock> start, end;
;
还是依照以前的习惯,写好时间计算类
3、定义数据结构
struct s_data
uint8_t* data = NULL;
size_t len = 0;
s_data(const char* in)
len = strlen(in);
data = (uint8_t*)malloc(len+1);
if (data == NULL)
return;
memcpy(data, in, len);
data[len] = '\\0';
~s_data()
if (data != NULL)
free(data);
;
typedef std::shared_ptr<s_data> ptr_s_data;
我们之所以使用智能指针,是希望程序直接释放,在不需要的时候直接内存放弃
4、boost 无锁队列
boost 无锁数据结构:以下摘自于boost文档
boost.lockfree implements three lock-free data structures:
boost::lockfree::queue
a lock-free multi-produced/multi-consumer queue
boost::lockfree::stack
a lock-free multi-produced/multi-consumer stack
boost::lockfree::spsc_queue
a wait-free single-producer/single-consumer queue (commonly known as ringbuffer)
下面我们使用spsc_queue
boost::lockfree::spsc_queue<ptr_s_data, boost::lockfree::capacity<100> > spsc_queue;
1、这是个单生产者,单消费者,多生产者,多消费者用处比较少,这里不使用,且以性能来说,spsc_queue的性能要高。高性能的程序不在于线程使用很多,而在于使用线程和内存以及cpu,gpu的合理性。
2、里面的100是指的程序缓冲,但值得注意的是:这个缓冲我们使用的是指针,而不是真实的数据空间。
使用指针空间意味着内存在外分配,我们成为带外分配,也就意味着内存容易撕裂。那我们应该怎么正确分配内存?一般来说,程序都会使用自己的内存管理,分配一个较大的内存,从中取得内存使用权限,有一个再分配管理。
int main()
if (spsc_queue.is_lock_free())
std::cout << "single producer, single consume" << std::endl;
//1000 second;// 000
TicToc tp;
std::thread thread_producer([=,&tp]()
//every ten millonsecond to
int insert_num = 0;
for (;;)
if (spsc_queue.write_available())
char buffer[128];
sprintf(buffer, "this is test %d\\n", insert_num);
ptr_s_data obj = std::make_shared<s_data>(buffer);
spsc_queue.push(obj);
if (insert_num++ > 100000)
break;
//condition_producers.notify_one();
else
boost::this_thread::sleep(1);
std::cout << tp.toc()<< " the insert is over " << std::endl;
);
std::thread thread_consume([]()
TicToc tc;
while (!done)
std::unique_lock<std::mutex> ul(pro_mtx);
//condition_producers.wait(ul);// , []
if (spsc_queue.read_available() > 0)
ptr_s_data obj = nullptr;
spsc_queue.pop(obj);
ncount++;
if (obj && obj->data != NULL)
if ((ncount % 10000) == 0)
std::cout << obj->data;
else
lee_mill(2);
std::cout << "left is " << spsc_queue.read_available() << std::endl;
std::cout << tc.toc() << " consume is over" << std::endl;
);
thread_producer.join();
done = true;
thread_consume.join();
return 1;
以下是执行的结果,看样子left是零,不过是巧合,生产者线程和消费者线程比较均衡。所以left 多少是与cpu 线程执行有关。剩余100 个,也是有可能的。读者可以自己调整,让其没有剩余,就是在退出循环之后,继续把剩余的执行完毕,然我们的目的不是这个,主要是为了哟用自己的内存管理单元,我们称之为mmu
上面的程序是直接分配内存,删除内存,并没有内存管理,那么如果做到内存管理呢,我们必须制作自己的mmu。
5、mmu内存管理单元
这是我前面的内存池文章
上面这篇文章讨论了内存池的制作,我们使用mmu,就是要在内存池上更上一个台阶,能够达到管理的作用,这个下一节再讲了
以上是关于c++千万数据级别正确使用无锁队列,避免内存撕碎的主要内容,如果未能解决你的问题,请参考以下文章