Archive for C/C++

我在当当买了一本笑谈大先生,陈丹青写的,大先生是鲁迅。
我花了两个晚上,把它看完了。
书是陈丹青演讲稿的集子,通常,演讲稿里总会有些废话,滥调;这本书的好处是这些寻常的演讲里有很多精彩的议论。

Clean Code, Uncle Bob的书。这本书豆瓣上好评如云。我零零碎碎的看了大概3/4,老实说,我有点失望。它或许对你的胃口,但它不对一个靠谱的,有理想的,心怀傲气的程序员的胃口,哈哈,你自己看看就知道我为什么这么说了。

观止-微软创建NT和未来的夺命狂奔,这本书看的我的我心潮澎湃啊。有兄弟说拿到手后通宵看了一晚上,就是停不下来。我也停不下来的看。

最近看了Effective C++C++ Primer,并且单独做了两个还蛮算重要的C++项目(都是分布式文件系统),我觉得我开始慢慢步入靠谱的C++程序员的行列了。不过,等我尝试去细读STL(因为我发现libstdc++的实现总是有许多奇怪的问题,甚至都不敢深入的使用STL,因此才打算细读)实现的时候,我发现我的生命被迅速的浪费了。我又买了一本More Effective C++。我打算再看看这本书,我的CPP之路或许最远也只能走到这里。不知道有没有兄弟觉得微软的STL实现要不libstdc++好?

做为一个自觉已经靠谱的Java程序员,我已经很少看Java的书了,现在市面上也确实没啥可看的Java书。

这两天在看TCP/IP高效编程TCP/IP卷3。做了两年的后端,我觉得自己对网络编程有了蛮多零碎的了解,但缺乏系统性。于是买了这两本书看。不过这也仅仅是两本零碎的书,果然,要想破除这种零碎的感觉,似乎除了看RFC别无它法?

Leave a Comment

BUG

本来上一篇日志是: Java与性能,写了一半,发现实在是心有余而力不足,于是就让它躺在了草稿箱,等将来对这个问题有更深入了解的时候,再写。

1月份开始感冒,之后就是好不了的咳,脑子都咳坏了,写代码时考虑不周,结构不好,BUG多多,清醒的脑子跟不清醒的脑子差别还真是蛮大的。

第一个麻烦是日志。

我接手的一个CPP 写的系统,用的日志系统是自己做的,为了支持32位机器,我给它增加了一个快到2G时,就按size轮转的机制,没想到这样一个简单的功能竟然出现了3个BUG,折腾了我快1天,SA被我折腾了好几次。

第二个麻烦是一个Java写的Mail相关系统。

为了支持Mail解析器可以不堵塞的写入数据到分布式存储系统,我在这两者之间加了Buffer层,这个Buffer由内存和文件组成。后来有了新的需求,需要有多个观察者观察Buffer上的数据变动,以便异步的将数据组装并发送给不同的需要数据的Server(比如,反垃圾服务)。

  1. 我第一个土鳖的地方是:Buffer上的观察者引用计数计算错误,从而导致Buffer用完后无法被收回;
  2. 第二个土鳖的地方是:采用了可重入(每个观察者拿到的是独立的Buffer对象,虽然它们底层的数据存储部分是共享的)的方式来读Buffer(DataBuffer.read(buf, off, len, bufPossion),可虑到内存Buffer,该可重入方式实现简单,就算是文件做的Buffer,在内核较新的Linux Server上,该操作也可以被映射为(ssize_t pread(int fildes, void *buf, size_t nbyte, off_t offset);的系统调用),不用加锁,非常迅速。这种考虑其实是不错的,但是我竟然忘了自己去维护当前的POSITION,导致buf永远从position 0开始读数据。
  3. 第三个土鳖的地方是:在向外写数据时,我用了Mina框架来维护客户端和数据传输。我写了类似代码:
    if (cachePosition > 0) {
    buffer = IoBuffer.wrap(cache, 0, cachePosition);
    session.write(buffer);
    }

    悲剧的是cache是一个byte array buf, 就是说该方法调用完后,cache是完全可能被新的数据更新的,可是,IoBuffer is backed by cache. session.write()又是异步的,这就导致了一件悲剧的事情:真正发生的数据可能乱掉,或者被覆盖掉。最后改成了:

    if (cachePosition > 0) {
    buffer = IoBuffer.wrap(cache, 0, cachePosition);
    WriteFuture future = session.write(buffer);
    future.awaitUninterruptibly();
    }

    这个悲剧的事情折腾了我1整天,写了n多测试代码来找原因。
  4. 其他还有一堆考虑不周,架构乱的土鳖地方。

头脑要清醒,能力急需提高啊

Leave a Comment

关闭一个线程

注意:由于个人能力及知识水平问题,以下内容可能有原则性错误,请批判着阅读!

最近搜东西,又搜到了这个关于pthread_kill的话题,相信有不少人看过这个讨论。NPTL的作者真霸道。看了几遍pthread_kill的手册,然后放心的写代码,然后得到一个core dump,相信谁都会不爽的。

但用pthread_kill(pid, 0)来检测一个线程的运行情况是一件不靠谱的行为,虽然这是非常普遍的行为:Joinable的线程完结了,还没执行pthread_join(),这个状态,pthread_kill(pid, 0)能正常识别么?规范没有说,其实很多实现都没有能够区分这两种状态吧。(1 运行中, 2 运行结束,还没join)还有一种比较不大可能发生的事情——通常,你的代码能提前发现这个问题:pid如果被重用了呢?这种时候,其实你检查的是一个全新的线程。

pthread_kill()是一个非常难用的方法,在确定你的线程能正确的处理信号之前,不能随意的向某个线程发出信号;如果你的程序不能正确处理,你的整个系统都会由于这个方法的调用而终止。出于对其的害怕,我从来没有在自己的代码里使用过它。

如果要关闭一个Server线程,其实可以为线程提供一个shutdown()方法,像所有Java程序员都会的那样;如果要立刻终止一个线程,可以用pthread_cancel(pthread_t),当然这个方法也会有风险(你不知道你要关闭的线程是不是已经终止了,你也不知道你要关闭的线程或许是一个全新的线程)。所以,pthread_cancel(pthread_t)方法需要在同步块内调用,调用前,确认 线程处于有效的状态。而线程也需要在同步块内才能改变自己的状态。

我觉得安全的做法,不论是pthread_cancel,或是pthread_kill,都需要利用同步机制,确认线程先有效,再操作。当然,很多人不这么认为,因为他们的代码从不这样写。 :)

Leave a Comment