2012年5月29日星期二

台湾同胞不该与日本军人开战

转载:台湾同胞不该与日本军人开战


【电影《赛德克·巴莱》观后感】我认为台湾同胞不该与日本军人开战。这是一场不可能打赢的战争。既然打不赢,就不应该去打。否则只能作出无谓的牺牲,让年轻人、孩子和妇女白白送命,甚至导致整个民族几近灭绝。



……
顺便说一句,我觉得台湾赛德克族同胞没有见过更可耻更可恶的统治者。日本统治者当时至少没有没收他们的全部土地和财产,没有搞个大跃进活活饿死无数百姓,没有发动文革让他们夫妻反目互相揭发互相批斗。更加可耻的统治者他们没见过。
……






新浪微博链接在这里

单例安全性


单例安全性

# 单例模式

单例模式,一种用于确保整个应用程序中只有一个类实例且这个实例所占资源在整个应用程序中是共享时的程序设计模式。
关于单件模式的更多讲解可以参见维基百科百度百科这里

# 实现模式
(转自维基百科)
实现单例模式的思路是:一个类能返回对象一个引用(永远是同一个)和一个获得该实例的方法(必须是静态方法,通常使用getInstance这个名称);当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用;同时我们还将该类的构造函数定义为私有方法,这样其他处的代码就无法通过调用该类的构造函数来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例。
单例模式在多线程的应用场合下必须小心使用。如果当唯一实例尚未创建时,有两个线程同时调用创建方法,那么它们同时没有检测到唯一实例的存在,从而同时各自创建了一个实例,这样就有两个实例被构造出来,从而违反了单例模式中实例唯一的原则。 解决这个问题的办法是为指示类是否已经实例化的变量提供一个互斥锁(虽然这样会降低效率)。

# 单例安全性


由于保证单例唯一性,引进互斥锁导致效率的问题,其实存在某种良好的解决办法的。
综上所述,对于单例模式,其具体的程序实现(方案)要点概括如下:对于单例模式,其具体的程序实现(方案)要点概括如下:
1 单例对象延迟加载(构造),。即使用的时候(获取时)才给予申请构造。

2 获取单例对象时,“双重检测”(判断)是否需要构造对象,。可解决上述的效率问题。

在此,我想说更多的是“双重检测”技术,保证单例对象的多线程访问安全性。

# 示例说明
去年,项目组的周会讨论过,关于创建件模式的安全性问题。那时候,我‘引荐’了“双重检测”该方法,同时提到Loki类库实现单例模式的做法。当时,大家却表现“未曾相识”的感觉,所以我那天晚上发了一段解释到项目组的邮件群。如下:
……
之前的周会讨论过,关于创建件模式的安全性问题。大家是否还有印象? **同学应该还有印象的吧,呵呵!
好像大家对此了解不多,所以我晚上在家里翻出了Loki老代码查看对照了下,在此稍微总结下,和大家一起分享和讨论。

Loki泛型类库实现件,使用的是“双检测”件对象,保证创建安全。见图说明:



btw:
附件 -- Loki件的实现。

至于Loki类库是什么,大家可以google下就知道了!
先描述这么多吧,有情况再讨论。
--

(完)

2012年5月27日星期日

锁,编程你需要知道的!

锁的归纳
     -- windows系统编程的锁(Linux系统类似)

lock & unlock


# 锁的概念
当然,在此要讲述的锁并非生活中的锁(门锁,车锁等)。而是编程世界的锁。
锁,在并发程序逻辑中保证某操作的同步性的一利器。该并发包括多线程与多进程(的线程)两种情况。
举个例子说明情况吧,如下:

Lock lock;
Job job;

func1()
{// run in thread1 or program1.
     do_lock(lock);
     handle(job);
     ... 
}

func2()
{// run in thread2 or program2.
     do_lock(lock);
     handle(job);
     ... 
}

这样,借助锁变量lock的同步操作,就可以保证处理事务job的原子性。在同一时刻只允许在一个地方处理事务job。
若时刻t,程序先进入func1执行handle(job)但未完成时,lock已被加锁,那么同时再进入func2时候由于lock已被加锁,导致程序会停在等待lock被解锁。
直到执行handle(job)完成,func2得到锁了才开始执行handle(job)。反之亦然。

# 锁的抽象设计

锁,最关键的两个操作:
a. 加锁
b. 解锁
而其构造函数,需根据不同实现方案而定。其他的操作可根据不同需求情况而定。

一般情况,锁都不希望被设计成具有可复制性。

比如我之前设计过的锁,示例如下:
class locker
{
    LIMIT_COPY_AND_ASSIGN_CTOR(locker)

public:
    locker();
     ... other constructor ...
    virtual ~locker() {}
     // main func
    virtual bool lock() = 0;
    virtual bool unlock() = 0;

     // extended func
    virtual bool is_valid() const;
    HANDLE handle() const;
    string_t name() const;
    int get_wait_ret() const;
    unsigned get_wait_time() const;
    void set_wait_time(unsigned wait_time);
    int error() const;
     ... other ...

protected:
    ... member var ...
};

在面向对象编程,我们一般把加锁与解锁的操作对应到一起,设计一个类型将两者包含,一个在构造函数,一个在析构函数。这样做可以保证加锁与解锁的对称性,不管程序中途返回或抛出异常,锁都是安全的。其设计很简单,如下:


template
 <class _Locker>
class scoped_lock_t
{
public:
    scoped_lock_t( _Locker& mutex_obj )
        : _locker(mutex_obj)
    {
        bool lock_ret = _locker.lock();
        assert (lock_ret);
    }
    ~scoped_lock_t()
    {
        bool lock_ret = _locker.unlock();
        assert (lock_ret);
    }
private:
    _Locker& _locker;
};

typedef scoped_lock_t<locker> scoped_lock;


锁的实现方案
     --(windows系统编程实现方案)
1.  互斥变量
Mutex functionDescription
CreateMutexCreates or opens a named or unnamed mutex object.
CreateMutexExCreates or opens a named or unnamed mutex object and returns a handle to the object.
OpenMutexOpens an existing named mutex object.
ReleaseMutexReleases ownership of the specified mutex object.

2. 事件
Event functionDescription
CreateEventCreates or opens a named or unnamed event object.
CreateEventExCreates or opens a named or unnamed event object and returns a handle to the object.
OpenEventOpens an existing named event object.
PulseEventSets the specified event object to the signaled state and then resets it to the nonsignaled state after releasing the appropriate number of waiting threads.
ResetEventSets the specified event object to the nonsignaled state.
SetEventSets the specified event object to the signaled state.

3. 信号量
Semaphore functionDescription
CreateSemaphoreCreates or opens a named or unnamed semaphore object.
CreateSemaphoreExCreates or opens a named or unnamed semaphore object and returns a handle to the object.
OpenSemaphoreOpens an existing named semaphore object.
ReleaseSemaphoreIncreases the count of the specified semaphore object by a specified amount.

4. 临界区变量
Critical section functionDescription
DeleteCriticalSectionReleases all resources used by an unowned critical section object.
EnterCriticalSectionWaits for ownership of the specified critical section object.
InitializeCriticalSectionInitializes a critical section object.
InitializeCriticalSectionAndSpinCountInitializes a critical section object and sets the spin count for the critical section.
InitializeCriticalSectionExInitializes a critical section object with a spin count and optional flags.
LeaveCriticalSectionReleases ownership of the specified critical section object.
SetCriticalSectionSpinCountSets the spin count for the specified critical section.
TryEnterCriticalSectionAttempts to enter a critical section without blocking.

还有其他,详见msdn


线程间的加锁
以上描述到实现方案,都适用于线程间的加锁操作。但是不同锁有不同的用法,效率也不同。
信号量与其他三者的用法不同,其不仅仅具备加锁解锁的功能。信号量对象对线程的同步方式不同于其他,信号量允许多个线程同时使用共享资源 ,这与操作系统中的PV操作相同。

注意仅限于线程间使用的锁,其效率较高,如临界区对象。

之间区别的更详细说明可以参考这里这里

进程间的加锁
上述四种具体的实现方案,除了临界区对象,其他三者都适用于进程间的加锁操作,并且三者创建的对象都是windows系统的内核对象。由于属于内核对象那么系统需要在内核层负责管理这些对象的属性与操作,所以这三者内核对象加锁(解锁)的效率要低于临界区对象。

锁的效率问题
不同锁之间有不同的效率问题。只要你明确该点,且理清并发场景与锁的具体使用情况。
当然,要是无需加锁操作就可以解决问题的实现方案,多半情况下就是最高效的方案了(哦,是对比于加锁方案)。

# 链接


2012年5月25日星期五

霍夫曼树一例(算法)

霍夫曼树一例(算法)
  -- Huffman-Tree应用一例



# Huffman-Tree
(搜集整理哈夫曼树理论知识)
给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman tree)。哈夫曼树又称为最优树。

霍夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数)。树的路径长度是从树根到每一结点的路径长度之和,记为WPL=(W1*L1+W2*L2+W3*L3+...+Wn*Ln),N个权值Wi(i=1,2,...n)构成一棵有N个叶结点的二叉树,相应的叶结点的路径长度为Li(i=1,2,...n)。可以证明霍夫曼树的WPL是最小的。

此算法的思想是:
(1)设给定的一组权值为{W1,W2,W3,……Wn},据此生成森林F={T1,T2,T3,……Tn},F 中的没棵二叉树只有一个带权为W1的根节点(i=1,2,……n)。
(2)在F中选取两棵根节点的权值最小和次小的二叉树作为左右构造一棵新的二叉树,新二叉树根节点的权值为其左、右子树根节点的权值之和。
(3)在F中删除这两棵最小和次小的二叉树,同时将新生成的二叉树并入森林中。
(4)重复(2)(3)过程直到F中只有一棵二叉树为止。

霍夫曼树

                    

# 问题描述
     (源自于Google groups论坛讨论,转)

问题:把一块长度为L的木棒切成N块,每段的大小必须为a1,a2,…,an,每一次切木棒的代价为当前木棒的长度,完成切割任务的最小代价?


# 测试案例

Input
首先输入T,有T个测试用例
每个测试用例输入两行
第一行整数L和N。接下来一行是N个数表示每一段的木棒长度。
Output
求完成任务的最小代价

Sample Input
2
10 4
1 2 3 4
306 8
120 37 42 42 32 2 7 24
Sample Output
19
785
# 解决方案

霍夫曼树解法的确是一种“美妙”的解决方案啊。
我刚开始看到这问题倒没想到霍夫曼。倒是其他思路,解法一。

> 解法一:
(存在问题)
1 降序排序集合A{a1,a2,…,an} 。

2 遍历集合A,计算每次切木棒代价cost_i。针对前后相同的元素,ai==aj,特殊计算:
     先切出木棒2*a1,再从2*ai木棒对半切分。
 
3 以上切木棒过程,累加不同cost_i,得到cost_sun即所求结果最小代价。


看似OK,跑了几个简单测试用例,包括上面的两个用例,均通过。不过想想觉得不太对劲。
可以猜想知道,对于复杂的测试案例结果就错误了。留给你稍微想想吧:-)

后来,实现了霍夫曼解法,对于比较复杂的案例,两种解法得到结果对比,终于可以明确解法一的不足地方了!

“反过来想每次合并是两段长度之和。于是就变成了Huffman问题了。”
“解释一下样例一,10分割为4和6,代价为10,6分割为3和3,代价为6,3分割为1和2,代价为3。总代价为10+6+3,即Huffman树中非叶节点的权值和。”

> 解法二:
1. 借助上述的霍夫曼算法,集合A {a1,a2,…,an}作为权值,构造霍夫曼树,即最优权值二叉树。
2. 累加所有非叶子节点的权值,即所求的结果最小代价。


# 链接



2012年5月23日星期三

深夜反恐(标题党)


深夜反恐(标题党)
     -- 201205游戏晚点过了 & 回忆大学那段日子


前几天有件事情说来很搞笑,回想想自己都觉得有些无语的,哈哈。

(故事)
晚上(加班)十点才回到家,忙这忙那的,然后洗完澡就闲下来轻松了,差不多也十一点半了啊。俩室友和我,三人都是大学同学哈,突然提起了CS反恐游戏,都表现出有些亢奋。果断,就开玩起来了。没想到这样一玩起就到深夜快两点了,诶。更让人无语的是,三人凑一队竟然跟电脑‘如火如荼’打着各种枪战。刚开始都有些手生,还被电脑虐了一把把的”惨不忍睹“了。后来手熟了配合起来了,三人才撑得住场面(PK过了电脑的专家抢手:-) 3 Vs 5)。


嘿嘿,我在此先承认,我们三都不是什么高手,也不是菜鸟抢手而已,就一般的水平吧。
好像退出了游戏,童鞋们才发觉,唉晚点了啊,真个杯具。
第二天,三人都要上班,苦逼的屌丝们啊。


但是,想说的重点不是这里。瞬间让我回忆起过去的一段美好时光,那是毕业季疯狂事情的其中一段子。

(回忆)
犹记得,2009-06 有那段时间(有一个多星期时间吧)连续着天天晚上到两三点的,半夜十二点了开始CS对战。一个寝室四人,2 Vs 2搞起,同样如火如荼。Junkun & Meng Vs Jinyu & Xiaoyong 有没有 ……

那时正值毕业季,论文答辩准备差不多了,反正有的是时间啊。晚上玩的很晚,白天基本睡到中午的,起床洗刷完了就奔食堂吃午饭了。日子看似很简单很颓废的样子,还时不时的聚餐喝酒啥的,诶。
一段时间下来,就时不时提醒自己”危机感“,明知这样不良作息时间对身体很不适啊,还这样持续着。哈哈,所以就担心担心啊(现在看回去当然是太多心太多心了)……

然后,论文答辩顺利完毕,就干脆回家休息几天吧,想好好调整调整作息习惯,养好身体啊,连后面评选优秀论文的机会也放弃了吧。毕竟之前答应了公司,一毕业了打算过去报到上班呢。身体第一嘛,否则谈何工作!

接着,回老家呆了十几天吧,各种休息各种玩,也有无聊的时候。后来,为了再奔回武汉参加毕业典礼,不想因为大学四年都过了最后竟然没参加毕业典礼而后悔,所以就从厦门飞武汉了,第二天就顺利参加了毕业典礼。那时候由于南方大量雨水天气导致南方地面交通各种艰难,只能靠着飞了!
其实参加了毕业典礼觉得也没啥的,不过还是应该的!毕竟……

最后,后面几天在学校平淡地度过,就顺利毕业离校了。20100629离开了武汉,0630下午到了珠海金山(公司)报到了。就这样开始工作了……

“深夜反恐”,其实是一件让人劳累的事情,虽然游戏娱乐,但当你游戏之后,一般都丝毫得到娱乐放松的效果。

(关键)
早睡早起,坚决、果断是个良好的习惯!最好,不要超过晚上十二点。望我遵循与坚持!


去年时候,一个好朋友,也是曾经的同事,闲聊时说起,“像我们刚毕业不久的,一定要照顾好,养好身体啊,以后打造自己事业时候才是真正需要用身体去打拼,去扛的时候,那时才是又苦又累的。”

2012年5月20日星期日

Story about C++ template



“模板”故事

     -- Story  about C++ template 201205 

# 故事背景

(故事)
好像我得先稍微抱怨吐槽几句才过把瘾,然后好继续谈谈我的C++ template故事。
诶,抱怨的不是C++语法喔,而是关于同事们对我的template观念的偏见,或曰误解。


某某同事们(包括现在的Leader :-) )‘抱怨’说,
“不喜欢,阿杜写的那坨坨模板代码。”
跟新人们,告诫的语气(哈哈)说,“不要学习阿杜那样用C++模板写代码。”
“代码,着实看起来比较牛B,但后来者需付出代价较大,尤其对于新手。”
……
当然,也有略微听闻到同事的一点赞声。嘿嘿 :-) :-)

所以,为表示‘无辜’,我想在此整理整理,关于C++ template的想法。

# 故事历程
     
边讲故事边总结吧 ……

其实,我对于模板的东西还是比较谨慎的,真的比较需要时才考虑使用。
他们好像不太理解(误解)我。要不然,就让我回忆回忆,梳理一番吧。

在XL快两年的项目开发中,主要使用到C++模板场景可罗列如下:
1. 实现繁多同类的网络通信协议,其中富有共性;
2. 实现字符流类型,针对协议不同字段编解码的字符流;
3. 实现可扩展置换(源码级)的调度策略(部分)。

(去年故事)
去年某月某日,项目组里讨论决定开发写代码时慎用C++模板,包括(禁用)C++异常等。
项目组Leader对于C++ template相对比较规避,他不喜欢。他相信,C++面向对象足以完成其所需了,足矣!
还有,组里其他几位主程对于C++ template不感冒,涉及不多。所以,我们就达成一致,慎用C++模板。

其实其实,我是中立者,那时候我已经很客观了!对于C++ template的利弊已心中有数,可用可不用,除非要用就用得恰处。
……

(更久以前的故事)
以前,我确实迷恋过C++ template,那是2009前还在大学时候,学习《STL源码剖析》《C++设计新思维》(Modern C++ Design)《C++ Templates》等模板书籍,还有研读STLLoki(部分)Boost库源码时候。毕竟,当时学习过程中,真的热衷于template,恨不得所有C++代码都用上模板,追逐各种奇淫技巧。
“有一点你要相信,借着C++ template有着完整自动机那样的推导功能,在泛型编程的世界里你无所不能。”这点就是当时的C++ template编程的信念。

那时候,针对模板方面,学习、测试性C++代码还保存着一些在硬盘上面,后来索性放到了Github保存着,以做纪念。有想待有时日与闲情,不妨翻翻,“温故而知新,不亦乐乎?”。

……

# 我的观点


我想说的很简单,我喜欢模板但不滥用,慎用模板只为了提高代码质量。

PS.其实,我一直有个想法,找时间好好整理一番,关于C++ template方面知识的的个人理解与总结,博文一篇。祝我早日完成,多谢。
(后续)
……


表示对C++ template 火星人,(美)Andrei Alexandrescu,的敬仰!


# 链接

2012年5月19日星期六

一个怪异的接口


一个怪异的接口
     -- 为了因糟糕接口而加班,而吐槽。
 



# 故事背景

     故事发生于2012-05-05,2012-05-12。


     接口声明如下:
      Long RequestGetInfo (TaskID taskId, Param param, Info info);
    输入:
       taskId,一个任务id标识针对某任务的请求。
       param,一系列的参数描述具体的请求,其中包含一属性session id区分不同调用者(详见后续部分)。
    输出:
       info,存放读取请求的结果。


     项目的需求,考虑在原来某功能函数的接口层实现过滤逻辑:
          过滤外界一样的调用者投递过来的一样(同参数)的请求。

# 规则描述

     为了能清楚的描述该逻辑,而不涉及过多具体细节,所以尽量以抽象形式描述,过滤规则两点如下:
     一、读取上次请求的结果,若处理逻辑已完成信息的返回则读取成功,否则失败。
     二、添加此次获取某信息的请求。

……

     以下描述两种不同的设计方案,”糟糕设计“与”良好设计“。

# 糟糕设计

     接口声明如下:
      Long RequestGetInfo (Param param, Info info);

     在原接口里修改,将过滤逻辑想办法增加进去。过滤逻辑有些复杂,需要完成的事情包括:
     a .  第一次函数调用,(一定)读取不到上次请求的结果,必须添加此次获取信息的请求。
     b1. 第二次函数调用,读取到上次请求的结果,但不添加此次的获取请求。

     b2. 第二次函数调用,未读取上次请求的结果(可能处理逻辑没来得及返回),也不添加此次的获取请求。
     下次函数调用,继续b1或b2步骤。
     c. 直到执行b1,后面的函数调用,则开始下面步骤,如下:
          c1 读取到上次结果,添加此次的获取请求。
          c2 未读取上次结果,不添加此次的获取请求。下次函数调用,继续步骤c。

     d. 补充一点,当外界调用(接口)者第一次调用时,接口层进去的业务层逻辑需分配之一个新的唯一session id给调用者。
          session id 用于区分不同(请求)调用者。需要由内部的业务层逻辑来负责完成分配session id该功能。

     最后,经多方面讨论以上的“糟糕设计”虽然可完成基本的过滤功能,但有一点它是完成不了的。区分出不同接口调用者。示例:
     callA     ---    RequestGetInfo (paramA, info)
     callB     ---    RequestGetInfo (paramB, info)
     callC     ---    RequestGetInfo (paramC, info)

     这样,当callA,callB,callC,都是首次过来请求,此时就RequestGetInfo 区分不出到底是谁调用,因为调用参数里不带有区分调用者身份的信息,参数paramA,paramB,paramC也完全可能是相同。该情况就很容易导致过滤逻辑出现错误。

     该接口现在不单纯是调用传递了,已经足够复杂了,虽然它处在接口层。而且还存在缺陷,可能导致结果错误。

# 良好设计

     接口声明如下:
      Long SubmitRequestGetInfo (Param param, Long resquetID);
      Long QueryRequestGetInfo ( Long resquetID, Info info);
      Long CreateSessionId (ID id);
     
     从几次“糟糕设计”的失败中,得出了一种可行方案,而且算是良好设计的方案。关键是,需要独立出该接口的不同部分,包括:
     a. 获取信息的请求 SubmitRequestGetInfo (...),接口层返回一个请求id给调用者;
     b. 调用者拿着请求id,读取上次请求的结果 QueryRequestGetInfo (...);
     c. 生成会话id以区分不同的会话请求 CreateSessionId (...)。

     这样做法改变了之前的思路,把过滤逻辑抛出去给调用者去关心了,而独立开以上三接口完全满足调用者使用需求,而且过滤逻辑看似‘淡淡’地消失了。调用者自己控制不重复请求的逻辑就很简单了,现在调用者需要逻辑描述如下:
     1. 请求获取信息之前,调用者需通过 CreateSessionId (...)得到一个会话id,以区分于其他调用者。
     2. 提交一个获取信息请求,返回一个请求ID。
     3. 用请求ID查询,信息结果是否返回。
          3.1 若结果返回,成功读取。则开始下一个获取信息,继续步骤2。
          3.2 若结果未返回,则等下次(定时)继续查询,继续步骤3。

     就这样,没了,足够简单的逻辑吧。在保证结果正确的前提下,其逻辑又清晰明了。

# 吐槽牢骚

     谁该做的事,而谁不该做的事,需要分得清楚,然后就各做各的的吧。简单即美!

     

2012年5月17日星期四

std::map的小小失误



std::map的小小失误


# 故事简介

完全属于我的脑子失误,短暂的弱智时刻,导致该失误的诞生,’罪过‘。
由于项目开发,需增加一逻辑:过滤同样的某接口调用的请求,保持内部响应逻辑处理系统不允许存在一个以上同样的请求。
请求内容包括ID和参数,两者可以区分出不同调用请求。
Request = { RequestID,RequestParam } 

# 失误情况

使用 std::multimap 结构做记录。添加、删除、测试(验证)记录条目。
详细定义,如下:

namespace query_lib
{
typedef std::multimap<int, std::pair<std::string, size_t> > request_record_type;
static request_record_type     _request_record;


/// 记录或标记函数功能请求 标记类型 pair<func_id, pair<func_param, record> >
bool add_request_record(const request_record_type::value_type& obj)
{
    /// Lock lock(...);// todo lock
    request_record_type::iterator lower_it = _request_record.upper_bound(obj.first);
    for (; lower_it != _request_record.end(); ++lower_it )
    {
        if (lower_it->first != obj.first)
            break;
        else if ( lower_it->second.first == obj.second.first)
        {
            ++lower_it->second.second;
            return false;
        }
    }
    _request_record.insert(lower_it, obj);
    return true;
}
/// 擦除函数功能请求的记录或标记 标记类型 pair<func_id, pair<func_param, record> >
void del_request_record(const request_record_type::value_type& obj)
{
    /// Lock lock(...);// todo lock
    request_record_type::iterator upper_it = _request_record.upper_bound(obj.first);
    request_record_type::iterator lower_it = _request_record.lower_bound(obj.first);

    for (request_record_type::iterator iter = upper_it; iter != lower_it; ++iter)
    {
        if (iter->first == obj.first && iter->second.first == obj.second.first)
        {
            if (0 != iter->second.second)
            {
                --(iter->second.second);
            }
            else
                assert(false);
        }

    }
}
bool test_request_record(const request_record_type::value_type& obj)
{
    /// Lock lock(...);// todo lock
    request_record_type::iterator upper_it = _request_record.upper_bound(obj.first);
    request_record_type::iterator lower_it = upper_it;
    for (; lower_it != _request_record.end();
        ++lower_it )
    {
        if (lower_it->first != obj.first)
            break;
        else if ( lower_it->second.first == obj.second.first &&
            obj.second.second != 0)
            return true;
    }
    return false;
}

# 问题解析
诶,简单一句话。颠倒了map::lower_bound & map::upper_bound两成员函数的含义。
罪过啊,浪费了设计,测试,调错,修改过程的数小时(3H+)时间啊,而且那时加班时间!
转,Look following ……
---
public member function

map::lower_bound

      iterator lower_bound ( const key_type& x );
const_iterator lower_bound ( const key_type& x ) const;
Return iterator to lower bound
Returns an iterator pointing to the first element in the container whose key does not compare less than x (using the container's comparison object), i.e. it is either equal or greater.

Unlike upper_bound, this member function returns an iterator to the element also if it compares equal to x and not only if it compares greater.


Notice that, internally, all the elements in a map container are always ordered by their keys following the criterion defined by its comparison object, therefore all the elements that follow the one returned by this function will have a key that compares greater than x.
---

举个明显的例子说明吧,如下:
map = { (1,a), (2, b), (2, c), (2, d), (3, e), (4, f) }

map.lower_bound(2) => (2, b)
map.lupper_bound(2) => (3, e)

# 忠告建议

     当你在想好了设计要开始编写算法逻辑的代码时,再次提醒“清晰确认使用的基本元素”!

# 链接

修改后,正确的程序参见链接页面

产品随想


产品随想
     -- 记录个人关于产品理念的小小看法


不同的产品,不同的公司发展。



一种优秀的产品,总是开始于人的确切需求,需持续关注,细微观察,发现之并将其产品化。

路漫漫兮,吾将上下而求索。
就个人眼光与思考,谈谈产品发展走向。纯属YY,侃侃而谈。
:-) 

1. 需求决定产品走向。示例如下:
     a. Yahoo的门户,汇聚了互联网主要(常用)网址的导航入口。正好符合了当时网民的上网导航需求,同时有效的实时信息。
      映射到国内有新浪,搜狐,网易三大门户。

     b. Google的搜索,整合了互联网大部门信息的页面索引。正好符合了当时网民的上网搜索需求。
      映射到国内有百度,搜搜等搜索引擎。

     注:这里仅简单描述了涉及到的公司的起步情况,当然了公司后续的发展还是逐步多元化地扩展出去的。如Google除了其搜索还有其Gmail、Google+、Picasa、Youtube等等很多……

2. 人性决定产品走向。示例:
     a. 苹果的产品,乔布斯的产品。乔帮主确认很伟大,(表示赞成很多人都这么赞美)他真正把产品做到了极致。其产品的特色很多涉及了人性的元素。以iPod,iTouch,iPhone为代表,好像每一步都有探水的嫌疑,每一步也都很成功,而且还循序渐进。简约而不简单。
     贪婪的人性弱点,人总是喜欢简单又美好的东西,但其内在要不简单(这正是iPhone极致所在)。简单的说就是,我们都喜欢那种看似简单、美观的好东西,但是其功能足矣,体验优美,iPhone当然就是一个很好的事实。
     似乎我的这样解释有些牵强,或许我的言辞不足以表达这种感觉,或许你比我更懂这种感觉那我不必多以解释了。

     b. 国内的微信(虽然Talkbox、米聊产品的研发在前),尤其摇一摇的功能。让N多的都市寂寞
     在中国都市尤其生活压力工作压力各种压力都繁重的一线城市,很多人在很多时候其内心都充满着寂寞与孤独,这就是这么类人的人性弱点。这时候微信的”摇一摇“功能正好可以一定程度上,弥补他们的寂寞与孤独。具体‘赞美’微信&张小龙内容参见  http://donglu.org/2012/02/2000 (转)
     ……

     虽然网上也有很多人对于微信的浮夸而破口大骂,那(微信)只是穿着马甲的QQ移动版。
     个人觉得,微信确实做得不错。至于他的负面,暂且围观。

最后,重复一遍主题:
一种优秀的产品,总是开始于人的确切需求,需持续关注,细微观察,发现之并将其产品化。


 Junkun Huang/ 2012-04-01/