C++ 非多线程安全实现Stream Part 1
来源:互联网 发布:卡拉宝 知乎 编辑:程序博客网 时间:2024/06/08 04:32
Stream (lazy sequences)是一种非常强大的数据结构,他只在我们使用一个元素的时候才会真正进行计算。这个性质就允许实现无限长的序列!比如整数的Stream。
Stream这种数据结构在函数式语言中很常见,比如scala中可以这样实现一个无限的Fibonacci数列
val fibs: Stream[BigInt] = BigInt(0) #:: BigInt(1) #:: fibs.zip(fibs.tail).map { n => n._1 + n._2 }在c++语言中并没有这样的支持,这篇博客里我要介绍如何用实现Stream。
Suspension
首先需要实现一个有用的功能: 一个可以暂停function执行的类Susp,Susp这个类可以保存一个function f, 在需要结果的时候再去进行实际的计算.
Susp.hpp
#ifndef SUSP_HPP#define SUSP_HPP#include <functional>template<typename T>class Susp {public: explicit Susp(std::function<T()> f) : _thunk(thunkForce), _f(f) {} T const& get() { return _thunk(this); }private:T const& getMemo(){return _memo;}T const& setMemo(){_memo = _f();_thunk = thunkGet;return _memo;}static T const& thunkForce(Susp * susp){return susp->setMemo();}static T const& thunkGet(Susp * susp){return susp->getMemo();}T const& (*_thunk)(Susp *); std::function<T()> _f; mutable T _memo;};#endif构造函数需要一个返回类型为T无需参数的函数f为参数。Susp的成员包括_f,f的复制;_memo用来保存计算过的结果;thunk一个函数指针通过修改这个指针的值可以达到第一次调用get的时候进行计算,之后对get的调用仅仅读取缓存。
Stream
Stream可以是空容器,或者包含一个Cell。一个Cell,为了达到可以获得一个value和Stream去掉第一个元素之后的尾巴的目的,需要包含一个value和一个Stream。
因为在概念上Stream和Cell都是immutable的,所以一个Stream包含一个表示Cell的shared_ptr,是安全的。
stream.hpp
#ifndef STREAM_HPP#define STREAM_HPP#include "Susp.hpp"#include <memory>#include <functional>template<class T> class Stream;template<class T>class Cell{public:Cell();Cell(T v, Stream<T> const& tail);explicit Cell(T v);T val() const;Stream<T> pop_front() const;private:T _v;Stream<T> _tail;};template<typename T>class Stream{public:Stream(std::function<Cell<T>()> f): _lazyCell(std::make_shared<Susp<Cell<T> > >(Susp<Cell<T> >(f))) {}Stream() {}~Stream() {}Stream(Stream const & stm) = default;Stream(Stream && stm): _lazyCell(std::move(stm._lazyCell)){}Stream& operator=(Stream && stm){_lazyCell = std::move(stm._lazyCell);return *this;}T get() const{return _lazyCell->get().val();}Stream<T> pop_front() const{return _lazyCell->get().pop_front();}bool is_empty() const{return !_lazyCell;}private:std::shared_ptr<Susp<Cell<T> > > _lazyCell;};template<class T> Cell<T>::Cell() {}template<class T> Cell<T>::Cell(T v, Stream<T> const& tail): _v(v), _tail(tail) {}template<class T> Cell<T>::Cell(T v) : _v(v) {}template<class T> T Cell<T>::val() const{return _v;}template<class T> Stream<T> Cell<T>::pop_front() const{return _tail;}#endif
一个Stream包含一个可以获得Cell的Susp,在第一次调用get或者pop_front的时候,才真正计算Cell。
看一个简单的例子Application.cpp
#include "stream.hpp"#include <iostream>Stream<int> ints(int n, int m){if (n > m){return Stream<int>();}return Stream<int>([n, m]() {return Cell<int>(n, ints(n+1, m));});}int main(int argc, char ** argv){Stream<int> stm = ints(1,10);while (!stm.is_empty()) {int a = stm.get();stm = stm.pop_front();std::cout << a << std::endl;}return 0;}
在例子中,构建了一个从n开始到m的Stream。Stream的初始化函数返回n,和一个从n+1到m的Stream。
附上Makefile
CC=g++CFLAGS=-std=c++11 -cLDFLAGS=SOURCES=Application.cppOBJECTS=$(SOURCES:.cpp=.o)EXECUTABLE=streamall: $(SOURCES) $(EXECUTABLE)$(EXECUTABLE): $(OBJECTS) $(CC) $(LDFLAGS) $(OBJECTS) -o $@.cpp.o:$(CC) $(CFLAGS) $< -o $@.PHONY: cleanclean:rm -f *~ *.o stream
这篇博客是我读博客的学习记录详情请见 http://bartoszmilewski.com/2014/04/21/getting-lazy-with-c/
在part 2中,我会记录Stream的用法和性质。
0 0
- C++ 非多线程安全实现Stream Part 1
- 【java】【多线程】线程安全与线程非安全【1】
- linux多线程编程(C):信号量实现的线程安全队列
- linux多线程编程(C):互斥量实现的线程安全队列
- HashMap实现多线程安全
- queue非线程安全及多线程解决办法
- 多线程之 线程安全与非线程安全
- 多线程之 线程安全与非线程安全
- 多线程之 线程安全与非线程安全
- 多线程之 线程安全与非线程安全
- 流处理时代(stream processing age)-part 1
- stream与C实现格式化 比较
- servlet如何实现多线程安全??
- servlet如何实现多线程安全??
- ThreadLocal,实现安全的多线程
- servlet如何实现多线程安全??
- (C#)安全、简单的Windows Forms多线程编程1
- C++stream
- OpenCV基础篇之绘图及RNG随机数对象
- OpenCV基础篇之像素访问
- 使用Pspice进行电路仿真
- OpenCV基础篇之图片叠加
- 循环的角度求均值
- C++ 非多线程安全实现Stream Part 1
- OpenCV基础篇之使用CMake管理工程
- OpenCV基础篇之查找表
- CentOS上编译安装OpenCV-2.3.1与ffmpeg-2.1.2
- OpenCV基础篇之读取显示图片
- OpenCV基础篇之像素操作对比度调节
- DSP/BIOS使用之初窥门径——滴答时钟及烧写Flash
- PCB设计资料:看到最后才知道是福利
- LabVIEW上位机与串口通信