11

实在很简陋,许多控制功能都没有实现:)
不过也能表现大致的框架吧。

/*
 * A simple process pool
 */
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
 
#include <sys/wait.h>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
 
#include <sys/mman.h>
#include <sys/select.h>
 
using namespace std;
 
int iProcessCount = 0;
int *pDispatchCount;
 
void InterruptHanler(int iSigno)
{
	//ToDo: kill all children
	cerr << "Dispatch Count: " << endl;
	for( unsigned int i = 0; i < iProcessCount; i++ )
	{
		cerr << i << "\t" << pDispatchCount[i] << endl;
	}
	exit(0);
}
 
//ToDo: replace two pipes with socketpair
int main(int argc, char **argv)
{
	if( argc == 2 )
	{
		iProcessCount = atoi(argv[1]);
	}
 
	if( iProcessCount <= 0 )
		iProcessCount = 10;
 
	int (*iPipeFD)[2] = new(int[iProcessCount][2]);
	int (*iNotifyPipeFD)[2] = new(int[iProcessCount][2]);;
	pDispatchCount = (int *)mmap(0, sizeof(int) * iProcessCount, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
 
	queue<int> queIdle;
	vector<int> vecBusy;
 
	for( unsigned int i = 0; i < iProcessCount; i++ )
	{
		if( pipe(iPipeFD[i]) == -1 )
		{
			cerr << "pipe error" << endl;
			return 0;	
		}
 
		if( pipe(iNotifyPipeFD[i]) == -1 )
		{
			cerr << "pipe error" << endl;
			return 0;	
		}
	}
 
	for( unsigned int i = 0; i < iProcessCount; i++ )
	{
		pid_t pid = fork();
		if( pid < 0 )
		{
			cerr << "fork error" << endl;
			return 0;
		}
 
		if( pid == 0 )	//child
		{
			int iCount = 0;
			while(1)
			{
				char sBuf[16] = {0};
				read( iPipeFD[i][0], sBuf, 15 );
				cout << i << ": " << getpid() << ", " << ++iCount << "\t" << sBuf << endl;
				pDispatchCount[i]++;
 
				//Do your work here
				int iMax = atoi(sBuf);
				usleep(iMax % 10000);
 
				write( iNotifyPipeFD[i][1], "1", 1);
			}
		}
 
		queIdle.push(i);
	}
 
	signal( SIGINT, InterruptHanler );
 
	int iCounter = 0;
	while( 1 ) 
	{
		if( queIdle.size() )
		{
			//Dispatch work
			char sBuf[16] = {0};
			int iRand = rand();
			snprintf(sBuf, 16, "%d", iRand);
 
			int iIndex = queIdle.front();
			queIdle.pop();
			write( iPipeFD[iIndex][1], sBuf, strlen(sBuf) );
			cout << "dispatch " << sBuf << " to " << iIndex << endl;
 
			vecBusy.push_back(iIndex);
		}
 
		cout << ++iCounter << "\t: queIdle.size = " << queIdle.size() << " vecBusy.size = " << vecBusy.size() << endl;
		//if( vecBusy.size() )
		{
			fd_set set;
			FD_ZERO(&set);
 
			int iMaxFD = 0;	
			for( unsigned int i = 0; i < vecBusy.size(); i++ )
			{
				int iIndex = vecBusy[i];
				FD_SET( iNotifyPipeFD[iIndex][0], &set);
				iMaxFD = max( iMaxFD, iNotifyPipeFD[iIndex][0]);
			}
 
			struct timeval timeout;
			timeout.tv_sec = 1;
			timeout.tv_usec = 0;
			select(iMaxFD + 1, &set, NULL, NULL, &timeout);
 
			for( vector<int>::iterator it = vecBusy.begin(); it != vecBusy.end(); )
			{
				int iIndex = *it;
				int iReadFD = iNotifyPipeFD[iIndex][0];
				if( FD_ISSET( iReadFD, &set ) )
				{
					queIdle.push(iIndex);
					it = vecBusy.erase(it);
				}
				else
				{
					it++;
				}
			}
		}
	}
 
	return 0;
}
09

闲来无事,翻看了Linux的CREDITS

里面只有三个中国人,其中两个是台湾的,剩下一个在北京,写过Freescale的USB驱动。

18

当可能出现几个进程争用(读、写)同一个Critical Section的时候,加锁是常用的做法。
Linux加锁的方法,除了经典的IPC(Semophore)之外,记录锁(Record Locking)提供了更简单的方法。

其实记录锁的名字叫文件锁会比较贴切一点,因为其加锁和解锁都是通过对文件的操作完成的。
文件锁的粒度大可到整个文件,小可到一个字节,长度可变,但都可以说是对应一个Record(逻辑意义上)。

对锁的控制是通过调用fcntl实现的,基本的方式如下:

fcntl(fd, operation, flock);

fd是某个文件的句柄,该fd需要以与type相匹配的方式open
operation是操作类型

  • F_GETLK 读取锁信息
  • F_SETLK 设置锁,在锁已经被占用的情况下,马上返回错误,有点类似于pthread的trylock
  • F_SETLKW 设置锁,如果锁被其他进程占用,则阻塞

flock是个struct,用来传递锁的详细信息

  • short int l_type 锁的类型,可以是F_RDLCK、 F_WRLCK、F_UNLCK,分别对应读锁、写锁和解锁
  • short int l_whence 与l_start一起决定锁的起始位置,SEEK_SET、SEEK_CUR、SEEK_END分别对应文件的开始、当前位置和末尾,和fseek、lseek里的含义一致
  • off_t l_start 起始位置
  • off_t l_len 长度,0表示从l_start到文件的末尾。据说某些实现支持负数
  • pid_t l_pid 拥有锁的进程,operation为GETLK的时候会被设置

fd所对应的文件,本身不需要有数据。

由operation的取值,flock的定义可以看出,其实记录锁非常灵活。
它既可以实现排他锁(F_WRLCK),也可以实现共享锁(F_RDLCK);
同时也支持同步锁(F_SETLKW)和异步锁(F_SETLK)。

记录锁的另一个好处时,进程退出时,会自动释放掉自己所占用的锁。
这就避免了进程异常退出时资源无法回收的问题。

速度也是需要考虑的因素,根据测试,记录锁相对最慢;
但综合考虑易用性和灵活性,我认为这样的速度损耗是可以接受的。

flock(2)是另一种实现文件锁的方法,详情可以man 2 flock。

Tagged with:
11

保存下来,以备不时之需

# /dev/sda8
UUID=2cf88d46-8b6e-4eb3-bc2f-5f0680983299 /               ext3    relatime,errors=remount-ro 0       1
# /dev/sda11
UUID=5822ad0d-4fc6-428f-9334-0a5d022a808d /usr            ext3    relatime,errors=remount-ro 0       1
# /dev/sda7
UUID=1c2431ce-68cf-4c10-89c9-f86a52389c9a /data            ext3    relatime,errors=remount-ro 0       1
# /dev/sda9
UUID=5c73fb68-6e3e-49e6-b7a8-0f21e9479aaa /home           ext3    relatime        0       2
# /dev/sda10
UUID=99e2d59c-28e5-47fb-a3c7-3ea3ca10aebb none            swap    sw              0       0
Tagged with:
07

升级到9.04之后,面板上的DropBox图标点击没有了反应。
直觉上是DropBox不支持Jaunty,
到DropBox的网站,没有发现支持Jaunty的版本。

遇到解决不了问题的时候,有两件事我的确定的:
1. 我不会是世界上第一个遇到这样问题的人;
2. 问题的答案通过Google可以找到。

这次也不例外,下面就是结果:)

cd ~
wget http://dl.getdropbox.com/u/17/dropbox-lnx.x86-0.6.491.tar.gz
rm -r .dropbox-dist/
tar xzf dropbox-lnx.x86-0.6.491.tar.gz
killall nautilus

这是来源

这只是临时解决方法,相信DropBox很快会有新版本发布。

Tagged with:
06

不是官方网站上声称的4.23,而是今天:)


升级中……

Tagged with:
03

找到了txt版本的天龙八部,准备放到手机上,但发现这个版本略有瑕疵。
可能是为了在固定宽度的显示器上显示的缘故,往往到了一定字数,文章就会折行。

萧峰道:“不行!”突然拍出一掌,击向木几,只听得劈拍一声响,木几碎成
数块,匕首随而跌落,凛然说道:“杀母大仇,岂可当作买卖交易?此仇能报便报,
如不能报,则我父子毕命于此便了。这等肮脏之事,岂是我萧氏父子所屑为?”

慕容博仰天大笑,朗声说道:“我素闻萧峰萧大侠才略盖世,识见非凡,殊不
知今日一见,竟虽个不明大义、徒逞意气的一勇之夫。嘿嘿,可笑啊可笑!”

萧峰知他是以言语相激,冷冷的道:“萧峰是英雄豪杰也罢,是凡夫俗子也罢,
总不能中你圈套,成为手中的杀人之刀。”

慕容博道:“食君之禄,忠君之事。你是大辽国这臣,欲只记得父母私仇,不
思尽忠报国,如何对得起大辽?”

萧峰蹭上一步,昂然说到:“你可曾见过边关之上、宋辽相互仇杀的惨状?可
曾见过宋人辽人妻离子散、家破人亡的情景?宋辽之间好容易罢兵数十年,倘若刀
兵再起,契丹铁骑侵入南朝,你可知将有多少宋人惨遭横死?多少辽人死于非命?”
他说到这里,想起当日雁门关外宋兵和辽兵相互打草谷的残酷情状,越说越响,又
道:“兵凶战危,世间岂有必胜之事?大宋兵多财足,只须有一二名将,率兵奋战,
大辽、吐蕃联手,未必便能取胜。咱们打一个血流成河,尸骨如山,欲让你慕容氏
来乘机兴复燕国,我对大辽尽忠报国,是在保土安民,而不是为了一己的荣华富贵,
因而杀人取地、建功立业。”

忽听得长窗外一个苍老的声音说道:“善哉,善哉!萧居士宅心仁厚,如此以
天下苍生为念,当真是菩萨心肠。”

这样的格式在640*480的屏幕上可能很好,但是在iPhone上看殊为不爽。
解决方法:

awk 'BEGIN{ while(getline){ if( $0 !~ /^$/ ) printf $0; else printf "\n" } }  END{printf "\n"}'  filename

找解决方法的过程中,发现了两个附加产品:

  1. 下载txt电子书的网站(不是论坛,无需注册,虽然广告很多)
  2. GNU的awk手册(比种种学习笔记要好得多)

曾尝试用sed,不果。

Update: 20090206
针对中文书,优化了一下

for f in *; do awk 'BEGIN{ while(getline){ if( $0 !~ /^[ \t\xa1]+/ ) printf $0; else printf "\r\n%s", $0 } }  END{printf "\n"}'  $f > $f.new; done

xA1A1是全角的\t

Tagged with:
十二 24

我肯定不是第一个不知道ls是怎么实现的人。
一般大家都知道怎么在linux下打开一个文件,然后读取里面的内容;
不过怎么样遍历一个目录,可能不少人还不太清楚用什么API。

下面是一个简单的ls demo程序,可以演示操作目录的模式。

#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
 
int ls(char *sPathName)
{
    DIR *dir = opendir(sPathName);
    if( dir == NULL )
    {
        printf("open %s fail.\n", sPathName);
        return -1;
    }
    chdir(sPathName);
    struct dirent *file;
    while( file = readdir( dir ) )
    {
#ifdef _DIRENT_HAVE_D_TYPE
        //如果是普通文件
        if( file-&gt;d_type &amp; DT_REG )
        {
            struct stat status;
            stat(file-&gt;d_name, &amp;status);
            printf("%20s last modified time: %d\n", file-&gt;d_name, int(status.st_mtime));
        }
        else
        {
            continue;
        }
#else
 
#endif
    }
    return 0;
}
 
int main(int c, char **v)
{
    return ls(v[1]);
}

ls的详细实现,可以在这里找到。

Tagged with:
十二 16

晚上用了一个小时试用libwww。

在ubuntu下编译遇到了不少问题,无论是编译库本身还是一些demo。
糟糕的体验,以及自从03年后这个库就没有更新过,所以决定放弃。

转向curl。

Tagged with:
十一 17

1.首先查看端口状态,可以使用命令
-># netstat -an   (若查看某个端口,后面可接端口号)

2.检查服务状态使用chkconfig,如检查SSH,
-># chkconfig sshd

如为off,则需要打开系统服务的端口,可用chkconfig on命令,如打开SSH,
-># chkconfig ssh on service xinetd restart

3.防火墙开放端口:

(方法一:)

i. 进入 /etc/sysconfig/ 目录,用 vi 命令编辑 SuSEfirewall2 文件,
-># vi SuSEfirewall2
在文件中找到FW_SERVICES_EXT_TCP,在其后面加上服务名或者是服务对应的端口,如SSH,
FW_SERVICES_EXT_TCP=”ssh” 或 FW_SERVICES_EXT_TCP=”22″
保存之后退出。

ii. 重启防火墙,以使配置生效,
-># rcSuEfirewall2 restart

(方法二:)

i. 进入 /etc/sysconfig/ 目录, 查找 iptables 文件。若不存在,则新建一个名为iptables文件,

-># touch iptables

ii. 在iptables文件中添加如下,以便打开端口,如:

-A RH-Firewall-1-INPUT -p tcp -m state -m tcp –dport 22 –state NEW -j ACCEPT
-A RH-Firewall-1-INPUT -p tcp -m state -m tcp –dport 80 –state NEW -j ACCEPT

iii. 重起iptalbes服务:service iptables restart  或重启机器。

iptables命令详解:http://www.diybl.com/course/6_system/linux/Linuxjs/200888/135058.html

(方法三:)

引自:http://hi.baidu.com/wzj423/blog/item/81e8d2f9525b995d242df23a.html 部分内容

创建/etc/init.d/firewall文件:

vi /etc/init.d/firewall

放到/etc/init.d下的原因是方便自动启动。

脚本如下:

#!/bin/bash
# This program is used to use start my iptables.
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:~/bin
export PATH

case “$1″ in
start)
echo -n “Staring FireWall …”
# /sbin/iptables -P INPUT DROP
/sbin/iptables -P OUTPUT ACCEPT
/sbin/iptables -A INPUT -i lo -j ACCEPT

/sbin/iptables -A INPUT -p tcp -m tcp –dport 22 -j ACCEPT
/sbin/iptables -A INPUT -p tcp -m tcp –dport 80 -j ACCEPT
/sbin/iptables -A INPUT -p all -m state –state ESTABLISHED,RELATED -j ACCEPT
/sbin/iptables -A INPUT -p all -m state –state INVALID,NEW -j DROP
echo “OK”

;;
stop)
echo -n “Stop FireWall … ”
/sbin/iptables -F
/sbin/iptables -X
/sbin/iptables -Z
echo “OK”
;;
restart)
/etc/init.d/firewall stop
/etc/init.d/firewall start

echo “Restart FireWall OK”
;;
*)
echo “Usage: $0 {start|stop|restart}”
esac

exit 0

如果想新开端口,直接修改start部分即可。

测试firewall是否能正常工作:

/etc/init.d/firewall restart

没有问题。

配置firewall随系统自动启动:

cd /etc/init.d
update-rc.d firewall defaults 01

01表示启动优先级,让系统刚启动时就立即启动防火墙规则,可修改所有的K01为K99,在关机或重启服务器时最后停止防火墙服务。

另:
ubuntu 下开发端口:http://wiki.ubuntu.org.cn/IptablesHowTo

Tagged with:
preload preload preload