有人要我挑战STL 质量, 很简单.

宏哥 发布于 2012/10/12 12:57
阅读 9K+
收藏 11

我很多年没有碰C++了, 下面是10年前的代码, 模板来做到数据类型无关, 用于在多个进程当中实现循环链表,用于消息队列. 新的版本,用一个局部对象,来实现锁.

实现这个的目的是在于通过设置固定大小内存空间, 实现对消息的动态内存分配, 为进程通信当中 1:N 的生产者/消费者模型服务

尽管当年很初级,但是这个库的工业强度, 质量,都远超STL. 10年, 不做任何修改,尽管不是那么漂亮, 但是足以达到24*7的强度标准, 过去的10年, C++ 的STL, Boost, MFC, 不知道多少烂Bug修复, 至今据说在等C++11, F K Them ALL!

STL不仅难以实现固定内存空间进行动态分配,更谈不上进程间共享, 那一大堆Allocator, 我就说一个词, Bullshit!!!!!

现在此代码对我无用,如果我重新实现它, 我会考虑用C

shmobjqueuenew.h.

/*
 * this file provide obj queue in share memory realization
 * composed by antony
 * 2003-3-17
 * copyright reserved
 */

#ifndef __SHMBOJQUEUE_H_
#define __SHMBOJQUEUE_H_
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
//#include "mylog.h"

template <class st> class shmobjqueue
{

	private:
		char *m_pShm;
		int m_iSemid;
		int m_iObjSize;
		int m_ipckey;

		//记录偏移量地址
		st *shmStart;
		st *shmEnd;
		st *first;
		st *last;

	typedef struct
	{
		unsigned int maxPoolSize;
		unsigned int actPoolSize;
		unsigned int exFirst;
		unsigned int exLast;
	}shmHead;

	shmHead *m_pShmHead;
	union semun {
			int val;
			struct semid_ds *buf;
			ushort *array;
	} arg;

	class guard
	{
		private:
			shmobjqueue<st> *p;
		public:
			guard (shmobjqueue<st> *);
			~guard();
	};

		char *shmcreate(int ipckey, unsigned long size);
		void asynInit(int ipckey);
		void asynStart();
		void asynEnd();

	public:
		//create memory to contain num st obj
		shmobjqueue(int ipckey, int num = 5000 );
		~shmobjqueue();
		//get a obj from pool
		bool get(st *);
		//put a obj to pool
		bool put(st *);
		//clear up all objs in pool
		void clearup();
		//detach from shm
		void detach();
		//return true if empty
		bool isEmpty();
		//return pool size
		int getSize();
		int getIpcKey();
		//return is full
		bool isFull();
}
;

template <class st > shmobjqueue<st>::shmobjqueue(int ipckey,int num)
{
	m_ipckey = ipckey;
	this->m_iObjSize = sizeof(st);
	//mylog("init queue shmobjqueue key=%x,size=%d", ipckey,this->m_iObjSize);
	//m_pShm = this->shmcreate(shmfilename, proj_id, num*this->m_iObjSize +sizeof(int)*4);
	m_pShm = this->shmcreate(ipckey, num);
	if(m_pShm == NULL)
	{
		assert(0);
	}
	else
	{
		//mylog("shm=%d",(int)m_pShm);
	}
	this->m_pShmHead = (shmHead *)this->m_pShm;
	if((int)m_pShmHead->maxPoolSize != num)
	{
		//mylog("max num %d,req count %d",m_pShmHead->maxPoolSize, num);
		assert(0);
	}
	this->asynInit(ipckey);
}

template <class st > shmobjqueue<st>::~shmobjqueue()
{
	//mylog("destruct[%x]",m_ipckey);
	this->detach();
}

template <class st > char* shmobjqueue<st>::shmcreate(int ipckey, unsigned long num)
{
	int shmid = 0;
	int size;
	key_t shmkey;

	if(num != 0)
		size = num*this->m_iObjSize +sizeof(shmHead);
	else
		size = 0;
	shmkey = ipckey;

	shmid = shmget( shmkey, size, 0640 );
	if( shmid < 0 )
	{
		shmid = shmget( shmkey, size, IPC_CREAT | 0640);
		if( shmid < 0 )
			return NULL;
		m_pShm = (char *) shmat( shmid, NULL, 0 );
		//m_pShm = (char *) shmat( shmid, NULL, SHM_RND );
		if( m_pShm == (char *)-1 )
			return NULL;
		memset( m_pShm, 0, size );
		m_pShmHead = (shmHead *)m_pShm;
		m_pShmHead->maxPoolSize = num;
		m_pShmHead->actPoolSize = 0;
		m_pShmHead->exFirst = 0;
		m_pShmHead->exLast = 0;

		//记录在类成员变量中,这些都是偏移地址
		this->shmStart = (st *)(m_pShm+sizeof(shmHead));
		this->shmEnd = (st *)(m_pShm+sizeof(shmHead)+sizeof(st)*num);
		this->first = this->shmStart ;
		this->last = this->shmStart ;
	}
	else
	{
		m_pShm = (char *) shmat( shmid, NULL, 0 );
		//mylog("attaching key=%d,shmid:%d,addr:%d",ipckey, shmid, int(m_pShm));
		m_pShmHead = (shmHead *)m_pShm;
			if( m_pShm == (void *)-1 )
		{
			//mylog("error:%s",strerror(errno));
				return NULL;
		}
		this->shmStart = (st *)(m_pShm+sizeof(shmHead));
		this->shmEnd = (st *)(m_pShm+sizeof(shmHead)+sizeof(st)*num);

		this->first = this->shmStart + m_pShmHead->exFirst;
		this->last = this->shmStart + m_pShmHead->exLast;
	}
	//mylog("last=%d", (int)this->last);
	return m_pShm;
}

template <class st > bool shmobjqueue<st>::get(st *p_st)
{
	bool ret;
	guard tmpGuard(this);
	//this->asynStart();
	if(m_pShmHead->actPoolSize >= m_pShmHead->maxPoolSize/2)
	{
		//mylog("danger pool key=%x , size %d", m_ipckey, m_pShmHead->actPoolSize);
	}
	if( m_pShmHead->actPoolSize <0)
	{
		ret =  false;
		//mylog("m_piPoolSize error:%d", m_pShmHead->actPoolSize);
		//force to clearup;
		this->clearup();
	}
	else if(m_pShmHead->actPoolSize == 0)
	{
		ret = false;
		//mylog("pool is empty");
		if(this->first != this->last )
		{
			//mylog("consistent error,%d,%d",(int)this->first, (int)this->last);
		}
	}
	else
	{
		ret = true;
		(m_pShmHead->actPoolSize)--;
		memcpy(p_st, this->first, sizeof(st));
		this->first ++;
		m_pShmHead->exFirst ++;
		if(this->first == this->shmEnd)
		{
			this->first = this->shmStart;
			m_pShmHead->exFirst = 0;
		}
		if(this->first == this->last)
		{
			m_pShmHead->actPoolSize = 0;
		}
	}
	//this->asynEnd();
	return ret;
}

template <class st > bool shmobjqueue<st>::put(st *p_st)
{
	bool ret;
	guard tmpGuard(this);
	//this->asynStart();
	if(m_pShmHead->actPoolSize >= m_pShmHead->maxPoolSize/2)
	{
		//mylog("danger pool key=%x , size %d", m_ipckey, m_pShmHead->actPoolSize);
	}
	if(m_pShmHead->actPoolSize >m_pShmHead->maxPoolSize)
	{

		//mylog("pool size error,max size:%d,actual size:%d",
			m_pShmHead->maxPoolSize,m_pShmHead->actPoolSize);
		ret =  false;
	}
	else if(m_pShmHead->actPoolSize ==m_pShmHead->maxPoolSize)
	{
		ret =  false;
		//mylog("pool is full,max size:%d",m_pShmHead->maxPoolSize);
		if(this->first != this->last )
		{
			//mylog("consistent error");
		}
	}
	else
	{
		ret = true;
		memcpy(this->last,p_st, sizeof(st));
		this->last++;
		m_pShmHead->exLast++;
		if(this->last == this->shmEnd)
		{
			this->last = this->shmStart;
			m_pShmHead->exLast = 0;
		}
		m_pShmHead->actPoolSize++;

	}
	//this->asynEnd();
	return  ret;
}

template <class st > void shmobjqueue<st>::clearup()
{
	guard tmpGuard(this);
	//this->asynStart();
	this->first = this->shmStart;
	this->last = this->shmStart;

	m_pShmHead->actPoolSize = 0;
	m_pShmHead->exFirst = 0;
	m_pShmHead->exLast = 0;
	//this->asynEnd();
}

template <class st > void shmobjqueue<st>::asynInit(int ipckey)
{
	key_t semkey;
	int value;
	semkey = ipckey;

	m_iSemid = semget(semkey, 0, 0640);
	if(m_iSemid <0)
	{

		m_iSemid = semget(semkey, 1, IPC_CREAT|0640);
		if(m_iSemid<0)
		{
			//mylog("error:%s",strerror( errno ));
		}
		arg.val = 1;
		value = semctl(m_iSemid,0, SETVAL, arg);
		//mylog("create sem value=%d",value);
		return;
	}
	else
	{
		value = semctl(m_iSemid,0, GETVAL, arg);
		//mylog("sem exist,value=%d",value);
		return;
	}
}

template <class st > void shmobjqueue<st>::asynStart()
{
	struct sembuf sops;
	int value;

	sops.sem_num=0;
	sops.sem_op=-1;
	sops.sem_flg=0;

	value = semop(m_iSemid,&sops,1);

	this->first = this->shmStart + m_pShmHead->exFirst;
	this->last = this->shmStart + m_pShmHead->exLast;
	//mylog("asyn start");
	return;
}

template <class st > void shmobjqueue<st>::asynEnd()
{
	struct sembuf sops;
	int value;

	sops.sem_num=0;
	sops.sem_op=1;
	sops.sem_flg=0;

	value = semop(m_iSemid,&sops,1);
	//mylog("asyn end");
	return;
}
template <class st > void shmobjqueue<st>::detach()
{
	if(m_pShm > (void *)0)
		shmdt(m_pShm);
	//mylog("ipckey=%x", m_ipckey);
}

template <class st > bool shmobjqueue<st>::isEmpty()
{
	if(m_pShmHead->actPoolSize == 0)
		return true;
	else
		return false;
}


template <class st > int shmobjqueue<st>::getSize()
{
	int l_size;
	guard tmpGuard(this);
	//asynStart();
	l_size = m_pShmHead->actPoolSize;
	//asynEnd();
	return l_size;
}

template <class st > int shmobjqueue<st>::getIpcKey()
{
	return m_ipckey;
}

template <class st > bool shmobjqueue<st>::isFull()
{
	bool l_bRet;
	guard tmpGuard(this);

	//asynStart();
	l_bRet = (m_pShmHead->actPoolSize == m_pShmHead->maxPoolSize);
	//asynEnd();
	return l_bRet;
}

template <class st > shmobjqueue<st>::guard::guard(shmobjqueue<st> *stp)
{
	this->p = stp;
	p->asynStart();
}

template <class st > shmobjqueue<st>::guard::~guard()
{
	p->asynEnd();
}
#endif

以下是问题补充:

@宏哥:@billzheng , 这种C++的奇技淫巧,个人觉得好玩意义. (2012/10/12 12:58)
@宏哥:代码看起来挺丑陋,但是不要紧, 没有任何修改的必要. STL, Boost很漂亮, 他们一直在修改. 这个代码完爆 Boost对应功能的模块, 在所有工业度量维度上. (2012/10/12 14:24)
@宏哥:写这个代代码大概要花一天时间, 比起学习STL, Boost这些垃圾, 还有调试他们的时间, 核算多了. (2012/10/12 14:26)
@宏哥:算法说明: 开辟一个大小为 header + sizeof(st) * N的共享内存块. 利用头记录 起止地址偏移量, 到尾部重新跳头. FIFO数据拷贝实现队列. (2012/10/12 19:33)
@宏哥:这个代码不是用来替代STL, 而是演示很简单的方法, 就能达到比STL更强的健壮性, 更简单的接口, 更高的性能, 仅此而已. 代码很差, 但是足够比STL的任何实现更好. (2012/10/13 10:55)
加载中
0
hanxh
hanxh

我觉得其实@宏哥 意思可以总结为,写个好用的,没问题的,覆盖面广c++库是不容易的。

那么就很有可能,等到库稳定了,黄瓜菜都凉了。写肯定还是能写出来的,不可能写不出来。 所以真要做面向对象,除非有必要,不该用c++。

3
灵剑子
灵剑子
stl的好处不仅仅在性能,若N个人使用它,能够在性能上强于M个人不使用它而自造的特定的轮子(N>M),那么这本身已经是一种成功。更别提使用公共库能够极大地降低项目中的学习与维护成本。
宏公公自吹得都快得道的人,如果在实际中自造的轮子都不如stl版本,那么我们应该鼓励大家继续自造轮子(质量参差不齐),还是使用stl(质量相对较高)?
宏公公其实就是一个在技术上见识很狭隘的人,这种人因为早期职业的成功(可能而已),从而将思维封固起来了,其实在中国有很多这样的技术主管,最终给公司带来了巨大的成本。
在这种人主管下的技术人员,被限制在本公司的业务中不能逃脱,因为除了本公司的业务,你在实践中并没有积累多少具备“可转移性”的技术基础。可有效防止员工跳槽。
billzheng
billzheng
回复 @郭煜 : 我们从来没有喷过高效的C容器,我们其实很推崇这些聪明才智。
billzheng
billzheng
回复 @郭煜 : 不知道宏哥怎么变宏公公的? 宏哥是在喷STL然后根本不知道STL, iterator,之后再秀了2段代码后,口口声声说是工业标准后,2颗蛋碎了,成公公了。
乌龟壳
乌龟壳
这个说法有点偷换概念哦。不用STL不等与不去复用代码,非STL的算法库,纯C的不少。宏哥也没反对复用那些质量高的。
billzheng
billzheng
宏公公这个名字不错!
2
billzheng
billzheng

引用来自“宏哥”的答案

回复 @billzheng :  我最后一次假定你是真的请教的, 哪怕再错一次, 回答关于STL为什么烂的.

简单直接点, 取其中个别:

Iterator : 我不知道这个东西, 和 for 循环相比, 除了制造麻烦, 还有什么

上面这些破玩意,有什么用, 解决了什么问题, 还是带来麻烦?

这种基本逻辑难道不懂吗?

.....................................

如果你不能理解上面说的这些简单的东西, 我只能说澳洲的那些留学生学校,太烂了.

@宏哥公公, 好几个亮点,你要讨论澳洲的教育先还是选择一个题目来讲? 

先将Iterator吧。简单的说Iterator就是就是指针,就跟你在C list里面进行遍历一样,+指针操作和*去内容。 让我问你一个问题吧,不用iterator, 你怎么设计你的C list及如何遍历队列, 如何实现队列上的算法? 你只会for??? 你的代码性能在哪里? sglib是你推崇的库,可是你居然不会用。  

给你看看for_each的实现吧,这就是全部代码? 给我们讲讲你的For的基本逻辑?

template<class InputIterator, class Function>
  Function for_each(InputIterator first, InputIterator last, Function f)
  {
    for ( ; first!=last; ++first ) f(*first);
    return f;
  }

魔方帅帅
魔方帅帅
回复 @billzheng : nice!
billzheng
billzheng
@魔方帅帅 兄弟,我没有留过学, 正在考虑继续进修一下.
魔方帅帅
魔方帅帅
回复 @billzheng : 我才知道你的实力居然是澳洲教育的问题,哎,后悔没去澳洲留学。
billzheng
billzheng
回复 @魔方帅帅 : Osc多了一个公公,玩玩也未必不可 :)
魔方帅帅
魔方帅帅
回复 @billzheng : 还是去stackoverflow玩吧,这里没啥玩的。
下一页
1
billzheng
billzheng

引用来自“宏哥”的答案

引用来自“魔方帅帅”的答案

我上次就说了boost里面有, @宏哥 没有听进去。

你可以对比一下, 历史更新记录, 

它是不是10年没有更新的代码, 还是解决了一大堆BUG.

没有人有兴趣等10年.

osc上有个Boost 高手, 能解决Boost的Bug的, 据说总是在等待新版本发布.

产品研发,不是这样的.

设备里面的代码,往往很多10年都不修改的. 人类才会进步

而不是永远等待新版本, 等待C+11

没有人阻止你写你自己的封装库,C也好,C++也好。10年前你有这个代码不等于别人的C++都烂,你天天喊C++很久了,你抛弃模板用你说的指针和宏(纯C)重新写一下你的这段代码,让我们学习学习?然后再在你的队列里面实现一些算法,实现消息priority,查找节点等功能?  

还有我怎么才能理解这句话呢? C怎么实现固定内存空间进行动态分配? 你自己用了共享内存库和STL什么关系? Aloocator需要你自己去写?

 @宏哥:STL不仅难以实现固定内存空间进行动态分配,更谈不上进程间共享, 那一大堆Allocator, 我就说一个词, Bullshit!!!!!

1
宏哥
宏哥

引用来自“魔方帅帅”的答案

@宏哥 ,我来了。我大部分的时间是花在裸机上做硬实时系统的,所以用的比较多的是C 

但是我经常会觉得,要是C里面多一些东西就好了,比如:我经常觉得,要是一个结构,能够在生命期结束的时候,我可以加入自己的代码就好了,C++的析构搞定了这个,或者是2个队列放入不同的元素在同一项目中,模板很好的解决了这些问题。我甚至在想,要是我不需要去写这么刻板但是又必须的引用计数该多好, shared_ptr也出现了。所以我有时候特别希望DSP,ARM编译器能够更好的支持C++。

我知道宏哥的经验很丰富,但是我说句真心话,@billzheng ,我从他的发言可以看出,他绝对是C++的老手,我估计10年应该最少了。虽然用工作年限评价一个人的水平显得太肤浅,但是他确实算是高手。我相信你也可以从我的过往发言中看出来,我不是开口乱说话的人。

C标准不过200页,C++标准700多页,可以看出C++的语义比C要丰富很多。确实需要花费更多的时间,才能够做出好的东西,这点我很认同,我更觉得C++的可怕之处在于用的人,而不是语言和库本身。所以,billzheng这么丰富的老手手中,我相信C++绝对是利器。

所以我觉得用什么语言跟人没有关系,我相信billzheng就是用PHP,也绝对是高手。

宏哥,我想请教下,你对STL如此反感,是不是碰到过很让人崩溃的案例呢?如果有的话 ,希望能跟我们分享一下。

 

C 和 C++最大的区别, 在于用它的人

用C的人,没有什么号研究C的, 用了几年,那点玩意, 早已唯手熟尔. 只能去开发产品, 比如电力控制设备

用C++的人, 10年之后, 还在研究语言新标准, 还在解决  STl, Boost的BUG. 好比你的现状, 你先在要做的不是去学习C++, 而是学习电力控制设备. C++给你带来的减值效应, 你学习了C++,所以不懂电力控制, 这就是成本. 并且,你开发出来的软件一定不稳定 -- 因为微软都做不到.甚至C++标准库,都做不到.

我学习C++的时候, 那个头文件到底有没有.h都是个问题. STL用起来非常Buggy, 我早先遇到很多问题,主要是内存分配, 是大问题

现在不用C++. 至于STL"可能"稳定了, 我只能说price is too high.

我也没有发现, 什么重要的软件是用STL开发的.

至于 billzheng , 他还停留在语言层面上,而不是工业层面考虑问题. 所以听不懂我在说什么.

"shared_ptr也出现了" 

-- 这说明更加要抛弃C++

-- 你要知道, C++诞生快30年了, 30年后, 你还好惊讶它有些新特性. 你不会永远年轻. 

 你如果用C, 就在上升层次, 用C++就是走回头路, 你最终还得回归简单.

mark35
mark35
所以对于mysq5.5性能比5.0提高一倍以上这种结果,我只能说mysql有够烂——都是v5这种版本级别了又不是增加了对性能有提升的新功能(比如pgsql的index-only scan),有这么高提升要么是构架很烂,要么是程序很烂
一千年前的人
一千年前的人
牛....
魔方帅帅
魔方帅帅
哈哈,我感叹shared_ptr是指我刚开始接触C++的时候,这个跟C++没关系。我只是因为需要那么做,才想着去找解决办法的。我理解你说的业务对我更重要,我是做现场通信的,C对我来说,只是工具而已,C++同样是,我只会在在需要的时候拿起合适的工具而已。
1
billzheng
billzheng

我一开始就是跟你请教到底STL哪一个地方不好,比如容器不好,算法不好,对象拷贝不好,Iterator不好,你直接跳到你的代码最好,对于自己的代码没法给出测试数据,没法说明在何种情况下性能最好, 还说我的要求? 你压根到现在还没有涉及到STL的具体知识好不好?

只会百度的程序员
只会百度的程序员
回复 @billzheng : 工业革命时期的标准。。。
灵剑子
灵剑子
回复 @billzheng : 铁道工业
billzheng
billzheng
回复 @魔方帅帅 : 他还一口一句他的代码是工业标准,这2年前的代码这水平,让我们怎么活? 这都工业标准(具体哪个工业就不知道了)了,我们怎么活?
魔方帅帅
魔方帅帅
回复 @billzheng : A比B好,是因为A就是比B好,你懂的。
billzheng
billzheng
回复 @醪糟儿蛋 : 宏哥吹捧C,结果他的C水平都10年左右了,还这样,怎么办? 蛋要破了....
下一页
1
CIW
CIW
弱者心态:      
  一个有着弱者心态的人是喜欢给优秀的人挑刺的。他们得不到所以就排斥。就说布什吧,好多人都很讨厌他(我自己对他也不大感冒),都在说他的坏话,可为什么我们只是说说,因为我们不够强大到可以去做的地步(思想的强大),便只好说葡萄酸了。如果你在精神上强大到可以不惧怕任何人,会影响大多数人的时候,你还会去说这样的话吗?毛泽东就是这样一个人!
       弱者心态是要不得的,虽然我们无法把他全部摒弃,但我们应该尽量不要有这样的弱者心态,这就要求我们时刻的学习,提高自己的思想境界、提高自己的核心竞争力!
       打败对手的最好方式不是去诋毁和诬蔑,而是让自己变得比对手更强大!
johnzhang68
johnzhang68
你的意思是美国或欧洲给中国挑刺或找茬是弱者心态?怎么不对美国讲讲你的理论?
0
billzheng
billzheng

 @宏哥说:

从奇技淫巧的角度说, STL Rocks, 把各种奇技淫巧用到极致

从质量, 商业,可用性角度说, STL 用极其糟糕,不为过

一个合格的C程序员, 随便写个算法, 比它5倍是很简单的.

然后现在开个贴,扔过来一堆10年by antony的代码,你的英文名是Antony? 通过学习这段代码,我们就能够领悟了STL, Boost有多烂了?


 

0
魔方帅帅
魔方帅帅
我也来凑个热闹先。嘿嘿
0
宏哥
宏哥

引用来自“billzheng”的答案

 @宏哥说:

从奇技淫巧的角度说, STL Rocks, 把各种奇技淫巧用到极致

从质量, 商业,可用性角度说, STL 用极其糟糕,不为过

一个合格的C程序员, 随便写个算法, 比它5倍是很简单的.

然后现在开个贴,扔过来一堆10年by antony的代码,你的英文名是Antony? 通过学习这段代码,我们就能够领悟了STL, Boost有多烂了?


 

你要质疑这个代码不是我写的,随便你. 本来也只是很简单, 很初级的代码. 

我告诉你的是, 在生产当中,要的质量标准, 是STL达不到的.

返回顶部
顶部