草肃威的布罗格

2011年3月2日星期三

多线程pipe

跟同事聊天时想到了这么个东西。

需求是现在有80G的日志,需要把这些日志按照某个规则,分类放到另外的8个文件里面去,每个文件代表一种类型的日志。

我的做法是起8个线程a[8]分析日志,8个线程b[8]写文件。这样a和b就是一个多对多的关系。对每一个a[i],b[0]到b[7]都回向它发送数据。如果使用vector或者是数组之类的结构的话,还得自己考虑锁的问题。

而如果使用pipe的话,a[i]负责往对应的pipe中写,b[i]在8个pipe上select或者epoll,就能很好避免掉自己管理各种竞态条件或者死锁。

唯一需要注意的问题是:每次读写的数据必须是小于PIPE_BUF的,这样才能保证读写的原子性。linux2.6.11之后PIPE_BUF的大小是65536。(参看 man 7 pipe)

另外,具体设计的时候,还需要考虑读写是否需要设置非阻塞等等。因为如果pipe的容量只有PIPE_BUF,如果满了,而且是阻塞式的写的话,当前线程式会阻塞在write操作上的。
--
caosuwei <caosuwei@gmail.com>

2011年1月27日星期四

autotools的复杂关系

autoscan生成configure.scan,手动将configure.scan重命名成configure.in
autoconf根据configure.in生成configure
automake根据Makefile.am生成Makefile.in
configure生成config.h(可选的),然后configure把config.h和Makefile.in当作输入生成Makefile

其中configure.scan重命名成configure.in后一般要根据需要手动修改下,可能是大改
Makefile.am是要手写

--
caosuwei

2011年1月11日星期二

hash表中取下标的一个小技巧

今天看redis的源码,看到了一个以前没见到过的技巧
int mask = hash_table_size - 1;
int index_in_hash_table = calculate_hash_key(key) & mask;
这是一个快速取得hash表中下标的算法
--
caosuwei <caosuwei@gmail.com>

2011年1月10日星期一

从别人那儿转来的

·         重构自己的代码如果是开发人员,随时要记得的事情是如何改善自己的代码质量。要让自己成为更好的技术人,重构或许是是随手可作的并且切实可以提高自己能力的一件事情。有好的代码为基础,才有可能随时面对更大的系统压力。要记住小网站有可能发展为大网站,技术人需要的是提前做好准备,为你的代码,为你自己,为你的团队。

·         自动化日常工作有人说,萝卜快了不洗泥,团队什么事情都要我做,我怎么有时间去搞什么重构?那么,是否可以将一些日常需要重复做的事情尽可能的自动化,比如日常发布是否 可以自动化?测试工作是否可以自动化?安全检查是否可以自动化?有了这些为前提,你肯定有足够的时间去做你想要做的事情。

·         良好的开发习惯在一个团队中,如果养成良好的开发习惯会让你节省时间和精力。比如对版本工具的掌握程度,如果连 SVN 都缺少使用意识的话,很难想象团队协作开发的时候会搞成什么样的局面。也不要抱怨团队的同事没有好习惯,他们或许正需要你的帮助呢...用你的行动,去带 动他们。顺便问一下,你平时为代码写注释么?

·         改进自己的产品复杂未必是最大的竞争力,细致精致有的时候是更好的竞争力。很多技术人员做到最后发现自己做了很多对用户并不重要的功能和产品,而最重要的产品反而疏于改进。这未必都是别人的错,如果自己能够对产品和业务有足够的了理解的话,你或许会驱动团队少走弯路,做更正确的事情。

·         提高资源使用率别人用数台机器支撑的访问量,换了你,能否用更少的硬件支撑?这些方案是可扩展的么?是可验证的么?遗憾的是,我看到多数小团队硬件利用率甚至比一些大团队更低。如果听任低效的代码、冗杂的产品功能不去改变,那么可能的确要面临资源利用率相对较低的窘境。

·         规划资源的能力团队小的时候,整个产品架构、整个网站架构的信息收集并不难,让你建立起一个全局的观念相对更为容易一些。注意分析整体架构的演变,根据自己的理解,一步一步预期将来可能出现的问题。这是非常难得的锻炼自己的机会。顺便问一下,你给自己的网站画过架构示意图么?

·         保持学习的热情我在前面说到了网络上的技术资源的丰富性,你是否能够持之以恒的去学习、吸收这些技术经验,是否养成了评估某项技术成熟度的能力? 什么,学了用不上?问题是再大的公司在技术上也是要有取舍的,更多的时候都是在用更为合适的技术而不是看起来更"先进"的技术。


--
tianyuan

2011年1月5日星期三

chdir带来的问题

今天帮同事看了一个小问题。本来这个问题不算什么,但是这个问题是我以前就碰到过,随手就解决了。然后这次反而花了一段时间才解决的。
问题是这样的,同事觉得自己的程序不够快,就想拿gprof测一下,结果发现程序一直都没有在当前目录下生成gmon.out文件。反复尝试了几次都不行,因为调用了我写的库,所以他跑来问我。我帮他查了快一个小时才查出问题来,当然这里面有程序运行的时间。原因是他在自己的代码里面调用了 chdir(),结果所有的gmon.out都写到了另外一个地方。

而我当时碰到这个问题的情形是找不到core文件。那时我想也没想,随手就在根目录下面 find了一把,一下子就找到了原因。

另外再说一句,今天看到LWN上说Linux kernel的2.6.37版有针对prof的更新。针对有动态链接的程序,还是得靠prof和Oprofile了。
--
caosuwei <caosuwei@gmail.com>

一个可以并行化的取取数组中第K大元素的算法

一个无序的数组A,长度是N,想要取出其中的第K大的元素.

1. 如果数组长度够小,那么对数组整体排序,取第K个
2. 如果数组长度太长,那么对数组做切分,对切分的每个部分排序,取出这个部分的中间元素.
3. 在中间元素中递归的取中间值,直到取出整个数组A中间值M.
4. 将整个数组A跟据这个中间值M划分为三个部分,大于M的,小于M的,和等于M的.
5. 根据这三个部分的大小来判断第k大的元素在哪个部分,对该部分递归的做上面的操作.

--
caosuwei <caosuwei@gmail.com>

lambda表达式

对于std::for_each()这样的算法,是最适合使用lambda表达式这样的小技巧的

lambda表示并不是一个必须的东西,跟它有相同作用的还有function object和函数指针.函数指针的缺点在于没办法保存中间状态,但是效率相对较高.而function object作为一个自定义类型当然能保持中间状态,但是写起来也太繁琐了.

lambda表达式算是综合了这个两个的优点.

这儿有一个例子

#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

int main()
{
// Create a vector object that contains 10 elements.
vector<int> v;
for (int i = 0; i < 10; ++i)
{
v.push_back(i);
}

// Count the number of even numbers in the vector by
// using the for_each function and a lambda expression.
int evenCount = 0;
for_each(v.begin(), v.end(), [&evenCount] (int n) {
cout << n;

if (n % 2 == 0)
{
cout << " is even " << endl;

// Increment the counter.
evenCount++;
}
else
{
cout << " is odd " << endl;
}
});

// Print the count of even numbers to the console.
cout << "There are " << evenCount
<< " even numbers in the vector." << endl;
}

总的来说,基本规则就是
1. [=], [&] 表示在lambda函数里可以访问当前所有变量,其中=隐含了this
2. [=, &a, &b] 表示除ab按引用传递,其他均按值传递
3. [a, &b] a按值传递,b按引用传递

这儿有个参考: http://msdn.microsoft.com/en-us/library/dd293599.aspx
g++ 4.5版本之后才支持这个东西, vc我没有查过,貌似也是vc2010才支持

--
caosuwei <caosuwei@gmail.com>

libssh2中的奇怪设定

最近用libssh2自己轮了一个scp函数出来,用到了 libssh2_userauth_publickey_fromfile() 这个接口,但是很奇怪的是,这个函数里做认证的时候,同时需要public key和private key作为参数, 任何一个为NULL都会导致认证失败,幸好最后一个passphrase参数可以为NULL

翻了翻libssh2的开发邮件列表,发现还有别人很烦这个东西,并且提供了一个patch,可以用NULL的public key而不会报错了.

链接在这里
--
caosuwei <caosuwei@gmail.com>

gcc -fPIC

不加fPIC编译出来的so,是要再加载时根据加载到的位置再次重定位的.(因为它里面的代码并不是位置无关代码)
如果被多个应用程序共同使用,那么它们必须每个程序维护一份so的代码副本了.(因为so被每个程序加载的位置都不同,显然这些重定位后的代码也不同,当然不能共享)
这样就失去了共享库的好处,实际上和静态库的区别并不大,在运行时占用的内存是类似的,仅仅是二进制代码占的硬盘空间小一些.而且在加载时才重定位的开销也很大(这一点使得这种做法更加没有意义).
--
caosuwei <caosuwei@gmail.com>

2011年1月2日星期日

2011年终总结

经过一年半的痛苦挣扎,终于咋去年年底得到了一份新的工作,当当网,有机会了解互联网行业,搜索,并发,大数据量处理等等技术。而且实际上,这份工作也开阔了我的眼界,并且在一些基础的语言细节和算法方面,也让我有了迅速和本质上的提高。
但是在四月底的时候,却迅速被辞退,然后投简历,面试。在推掉taobao的offer之后来到了现在这个刚起步的公司。如果可以说稳定的话,算是初步稳定下来了。
往回看看,毕业之后的去的那间公司完全是个失败的尝试,我并不适合去干嵌入式方面的公司,而且还是一个养老公司,几乎就是荒废了一年半时间。
3,4月份在当当的时候,迅速的把我以前自学过,但是一直没有实战机会的知识应用到了实际的项目中,这是一个加深和巩固的过程,最直接的好处就是在我到现在这个公司的时候,我的能力马上就得到了认可,隐隐已经是部门最好的人之一。但是这个似乎并不是算是一件好事:公司的技术力量并不强,项目组也并不需要多复杂的技术。项目组需要的是一个7×24稳定的系统。
当我的能力得到认可之后,我也就有了一定的自由度,这样我也就可以用这些时间研究一些开源的项目。2011年,我希望我能在某个开源项目中贡献出自己的代码。

今年的两次跳槽,我的工资从4k涨到了10k,比例不小,但是绝对值还是不大。希望2011能通过加薪或者跳槽至少到15k,或者翻倍。

在技术上,我不知道我现在这样能不能有大的突破了,或者还是去个大公司历练一下才是正途?

年中和年底和妈提起的在北京买房的计划随着北京房价的一路飙升和我一家人的犹豫不决彻底泡汤了,爸妈还是希望能在老家住套新房子,那样也好吧,老家的房子住了二十多年来,也该换换口味了。至于我的房子,还是靠我自己吧。

2011年,我已经奔向26岁了,工作上已经找到了自己的定位和方向,往前冲就是了。感情上和zm的还是犹豫不决,我不想去南京。身体上,到了2011,年纪已经不小了,锻炼已经要当成一件正式的任务来完成了。平时如果没事,去考个驾照吧。呵呵
--
tianyuan

2010年5月15日星期六

拆thinkpad T60 的Ctrl键

左边的ctrl下面卡了一个瓜子皮,怎么都到不出来了.
刚刚忙了半天,才把它弄好.还反复折腾了两次.第一次装上后,用力一会儿,觉得按
键反馈力度不对,但是不想弄了,毕竟是个蛮精细的东西.
结果忍了半天没忍住,实在是不爽,又把按键抠出来了.结果这回悲剧了.
X型的两个支架之间的卡笋被我弄断了一半,不过幸好还能用.忙活半天,也终于发现
了第一次装上后手感不对的原因了, ctrl按键的键帽上还有一个铁丝的U型支架,需
要套在X型支架旁边的两个铁环里面,这样力度才对.

弄断一半卡笋,弄明白了按键的结构,也算有得有失吧 -_-!
--
caosuwei <caosuwei@gmail.com>

2010年5月11日星期二

一个简单的sql

ID Name subject Score
1 小明 A 12
2 小明 B 20
3 小王 A 1
4 小明 C 100
5 小王 E 23
6 小张 A 33
7 小王 B 3

select name from (SELECT name, sum(score) as sum_score FROM `grade` group by Name) as temp where sum_score > 100;
--
caosuwei <caosuwei@gmail.com>

debian下mysql的配置

debian下的mysql默认是关掉了远程访问的功能的,需要手动打开.
从配置文件上可以看到,这个关闭并没有用skip-networking, 而是把 bind-address改到了回环地址上.
所以只要把地址改到对外的网卡地址上就行.
另外,还需要修改mysql.user表中指定用户的权限.
我现在的表中是
|Host |User|
% root
127.0.0.1 root
所以我直接把后一条记录删掉了.
--
caosuwei <caosuwei@gmail.com>

2010年5月3日星期一

取boost::thread调用函数的返回值

为了取thread调用的函数的返回值,以前要么是弄个函数包起来,用一个外部变量记录返回值,要不就是在类里面加个public的变量做记录,感觉很不地道,而且麻烦

最近看boost的文档,才发现原来1.41和以后的版本的thread库里面已经有相关的东西做这件事了

这个就是 boost::unique_future 和 boost::shared_future.

用起来很方便,下面是示例

#include <boost/thread.hpp>
#include <string>

using namespace std;
using namespace boost;

int calculate_the_answer_to_life_the_universe_and_everything(int par, string aaa)
{
if(aaa == "hello")
return par-1;
else
return par+1;
}

int main(void)
{
int a = 33;
string b = "hello";
boost::packaged_task<int> pt(boost::bind(calculate_the_answer_to_life_the_universe_and_everything, a, b));
boost::unique_future<int> fi=pt.get_future();

boost::thread task(boost::move(pt)); // launch task on a thread

fi.wait(); // wait for it to finish

assert(fi.is_ready());
assert(fi.has_value());
assert(!fi.has_exception());
assert(fi.get_state()==boost::future_state::ready);
// assert(fi.get()==42);
int aaa = fi.get();
return 0;
}
--
caosuwei <caosuwei@gmail.com>

在debian上安装wordpress

今天在我的debian虚拟机上装上的wordpress.
设置wordpress本身倒是件很简单的事情,主要就麻烦在配置php,mysql和apache.
debian上这些软件的配置文件的位置都挺奇怪的.找文档就费了不少时间.

1. 首先是安装mysql
这个简单,直接 apt-get install mysql-server就行了.
然后 mysql -u root -p
create database weblog, 建立一个叫weblog的数据库,等会儿给wordpress用.
mysql的配置文件在/etc/mysql/my.cnf

2. 安装php
我最初只是 apt-get install php5
后来发现这样php连不上数据库,访问apache服务器的时候会报连不上mysql的错误,
后来才知道应该再装一个 apt-get install php5-mysql.
php.ini文件的位置是/etc/php5/apache2/php.ini

安装这个的时候会顺便把apache一起装上的,apache的配置文件在/etc/apache2/
这个配置文件的嵌套层数很多,如果要修改DocumentRoot的话,这个设置在/etc/apache2/sites-available/default文件里面.

3. 安装wordpress
修改好DocumentRoot后,就可以把wordpress放到指定位置了.只需要修改wordpress配置文件中的DB_NAME, DB_USER, DB_PASSWORD这几个就行了.

4. apache
如果修改了apache的配置文件,可以用 /etc/init.d/apache2 restart 这个来重启apache服务器.
--
caosuwei <caosuwei@gmail.com>

2010年4月12日星期一

取boost::thread调用函数的返回值

为了取thread调用的函数的返回值,以前要么是弄个函数包起来,用一个外部变量记录返回值,要不就是在类里面加个public的变量做记录,感 觉很不地道,而且麻烦

最近看boost的文档,才发现原来1.41和以后的版本的thread库里面已经有相关的东西做这件事了

这个就是 boost::unique_futureboost::shared_future.

用起来很方便,下面是示例

#include <boost/thread.hpp>
#include <string>

using namespace std;
using namespace boost;

int calculate_the_answer_to_life_the_universe_and_everything(int par, string aaa)
{
    if(aaa == "hello")
        return par-1;
    else
        return par+1;
}

int main(void)
{
    int a = 33;
    string b = "hello";
    boost::packaged_task<int> pt(boost::bind(calculate_the_answer_to_life_the_universe_and_everything, a, b));
    boost::unique_future<int> fi=pt.get_future();

    boost::thread task(boost::move(pt)); // launch task on a thread

    fi.wait(); // wait for it to finish

    assert(fi.is_ready());
    assert(fi.has_value());
    assert(!fi.has_exception());
    assert(fi.get_state()==boost::future_state::ready);
//    assert(fi.get()==42);
    int aaa = fi.get();
    return 0;
}



--
caosuwei

2010年2月28日星期日

修改debian中网络接口的名称

从Windows 7换回xp后,我的virtualbox中的debian就不能上网了,本来应该是dhcp得到ip的,但现在根本就分配不到ip地址.

今天上网搜了一下这个问题.搞定了,在这里记录一下.

我的host系统换了之后,guest虚拟出来的网卡的mac地址也变了.结果guest启动的时候,就自动在/etc/udev/rules.d /70-persistent-net.rules里面加了一个网络接口,依次是eth0,eth1,eth2,eth3...

这几个接口唯一的区别就是mac地址不一样.

但是/etc/network/interfaces中默认启动并并配置dhcp的仍然是eth0,结果,当然eth3就分配不到ip,当然上不了网.

解决办法就是要么改网络接口名称,要么配置新接口的ip获得方式.

1.改网络接口名称

这个方法就是修改 /etc/udev/rules.d/70-persistent-net.rules 文件,把多余的项目删掉,或者注掉.只留下当前有用的.

2.配置新接口的ip获得方式

修改/etc/network/interfaces文件,加上

auto eth3 #自动启动eth3接口

allow-hostplug eth3 #eth3这个接口只有在插上网线的时候才回去连线

iface eth3 inet dhcp #这句就是设置dhcp了


以上配置文件路径是以debian 5.0.4为准.供参考.
--
caosuwei <caosuwei@gmail.com>

2009年12月23日星期三

取出一个文件夹中所有非源码的文件

 ls ./*.[^c,h]*

一个简单的正则,取出所有不是用c或者h开头,并且后缀是一个或者多个字符的文件,一般就是 .o文件, .la文件, .lo, .y文件这些编译的中间文件.



--
caosuwei

2009年9月29日星期二

秒表

我的诺基亚手机没有秒表,总要找同事借,干脆自己写了一个


精度是 microsecond


#include <iostream>
#include "boost/date_time/posix_time/posix_time.hpp"

using namespace std;
using namespace boost::posix_time;

int main(void){
    ptime start, suspend;
    start = microsec_clock::local_time();
    while(getchar()){
        suspend = microsec_clock::local_time();
        cout<< suspend - start<<endl;
    }
    return 0;
}

然后

g++ timer.cpp -o timer.exe -Ie:\boost_1_39_0\ -O2 -Wall

2009年9月1日星期二

asio中的同步读写操作

写了个利用sina的股票接口读取实时股票信息的程序,练习一下boost::asio的使用.
现阶段我用到的只是里面最简单的同步读写接口,异步方面的还用不上.
当时主要是卡在了asio::read, asio::read_until, ip::tcp::socket::read_some这几个读操作上面了.
最初我是直接把asio::read放到一个while循环里面
while(boost::asio::read(connfd, response_, boost::asio::transfer_at_least(1), error)){
......
}

一直读到无数据可读为止.
后来看到那个可怜的文档里面还有一个completion condition叫transfer_all(),可以不用循环一次读完数据
boost::asio::read(connfd, response_, boost::asio::transfer_all(), error)
但是这两种都会在判断"至少还有一个字节",或者"读完所有"上面等待很长时间.去邮件列表问了,也不知道为什么.只好换一个方法.
还有一个read_until,但是我要读的是个http包,没办法知道最后要读到什么限定符为止.
ip::tcp::socket类有个成员方法是read_some,用来读指定字节的数据.
我最终的方法是用read_until读完全部的http头,取得后面http包的字节数.然后就能用read_some读取指定字节数了.
但是这地方有个问题.
read_until读取的数据要比指定限定符位置的更多.调用完read_until之后需要把读取出来的限定符之后的数据都倒出来,
放到read_some里面的Content-Length参数也需要减去相应的字节数.因为这部分数据已经在read_until操作中读出来了.
处理完数据,取好剩余字节长度,就可以调用read_some了.

2009年7月30日星期四

D-Link DI-524M无线路由不好用

这个无线路由一点都不好用,设置不方便,无线信号不稳定.就我用过的tp-link的和
netgear的来说,d-link的是最差的.你们想买的人还是三思吧
--
caosuwei <caosuwei@gmail.com>