2009年5月29日星期五

Per 多线程共享数据的问题

我有个多线程的应用,要共享一个数据结构——一个按id分类访问的多队列,具体讲就是一个hash,hash键是id,hash值是一个匿名数组引用,匿名数组
的第一个元素是一个标量(队列的属性),匿名数组的第二个元素是一个匿名数组引用(队列的数据),非多线程写法就是如下:
my %queue;
$queue{$id} = [$scalar, [$to_handle_data1, $to_handle_data2, ...]];
现在要在多个线程间共享这个数据结构,我是这样写的:
use threads;
use threads::shared;

my %queue:share;
if (not exists $queue{$id}) {

$queue{$id} = &share([$scalar, &share([ $data1 ])]);

} else {

push(@{$queue{$id}->[1]}, $data2); #这句出错,导致线程终止
}

程序写出来,不能按我的期望那样跑,哪位熟悉的大侠,能帮我看看这种数据共享应该怎么写才正确呢,谢谢了!
=============================================
============================================
打印的错误消息:
thread failed to start: Invalid value for shared scalar at ./xxx.pl line 32.
=================================================
=============================================
解决了,正确的写法如下:
$queue{$id} = &share([]);
push(@{$queue{$id}}, $scalar);
push(@{$queue{$id}}, &share([]));
push(@{$queue{$id}->[1]}, $data);
=======================================
===========================================
函数前面不要写 &,空参数不要写 [],重复使用的 $queue{$id} 可以
再弄个变量代替,这样看起来容易。
=========================================
=========================================
我有些搞不懂为啥它不支持将一整个变量深层地share,非要对每个分量再次share. 技术上有难度吗?
================================================
==============================================
技术上难,使用上也难,因为涉及到引用,你可能无意中就共享了
一大堆东西,垃圾回收也不好做了,因为 Perl 里引用超出作用域
就销毁,如果多线程共享就不行了。

Perl中对hash的操作

=================

Perl Hash Howto

This how-to comes with no guaratees other than the fact that these code segments were copy/pasted from code that I wrote and ran successfully.

Initialize (clear, or empty) a hash

Assigning an empty list is the fastest method.

Solution

    my %hash = ();

Initialize (clear, or empty) a hash reference

People have asked how to initialize a hash reference (aka hash ref and href). This is the way to go:

Solution

    my $hash_ref = {};  # a reference to an empty hash, ref will return HASH

The great thing about this is that if before performing an actual assignment, you want to determine (using the ref operator) the type of thingy that a reference is pointing to, you can!... and you can expect it to be a HASH built-in type, because that is what the line above initializes it to be.

Note

If you treat the variable just as any scalar variable; and use the my declaration alone, or assign a value, ref will return false.

    my $hash_ref;
my $hash_ref = 0; # zero

Add a key/value pair to a hash

In the solutions below, quotes around the keys can be omitted when the keys are identifiers.

Hash:

Solution

    $hash{ 'key' } = 'value';    # hash
    $hash{ $key } = $value;      # hash, using variables

Hash reference:

Solution

    $href->{ 'key' } = 'value';  # hash ref
    $href->{ $key } = $value;    # hash ref, using variables

Add several key/value pairs to a hash

Solution

The following statements are equivalent, though the second one is more readable:

    %hash = ( 'key1', 'value1', 'key2', 'value2', 'key3', 'value3' );
    %hash = (
key1 => 'value1',
key2 => 'value2',
key3 => 'value3',
);

Copy a hash

Solution

    my %hash_copy = %hash;  # copy a hash
    my $href_copy = $href;  # copy a hash ref

Delete a single key/value pair

The solution differs for a hash and a hash reference, but both cases can use the delete function.

Solution

Hash:

    delete $hash{$key};

Hash reference:

    delete $hash_ref->{$key};

Perform an action on each key/value pair in a hash

The actions below print the key/value pairs.

Solution

Use each within a while loop. Note that each iterates over entries in an apparently random order, but that order is guaranteed to be the same for the functions keys and values.

    while ( my ($key, $value) = each(%hash) ) {
print "$key => $value\n";
}

A hash reference would be only slightly different:

    while ( my ($key, $value) = each(%$hash_ref) ) {
print "$key => $value\n";
}

Solution

Use keys with a for loop.

    for my $key ( keys %hash ) {
my $value = $hash{$key};
print "$key => $value\n";
}

Example

    my $file = $ARGV[0] || "-";
my %from = ();
open FILE, "< $file" or die "Can't open $file : $!";
while( ) {
if (/^From: (.*)/) { $from{$1}++ } # count recurrences of sender
}
close FILE;
for my $sender ( sort keys %from ) {
print "$sender: $from{$sender}\n";
}

Get the size of a hash

Solution

    print "size of hash:  " . keys( %hash ) . ".\n";

Solution

    my $i = 0;
$i += scalar keys %$hash_ref; # method 1: explicit scalar context
$i += keys %$hash_ref; # method 2: implicit scalar context

Use hash references

Solution

    sub foo
{
my $hash_ref;
$hash_ref->{ 'key1' } = 'value1';
$hash_ref->{ 'key2' } = 'value2';
$hash_ref->{ 'key3' } = 'value3';
return $hash_ref;
}
my $hash_ref = foo();
print "the keys... ", sort keys %$hash_ref, "...\n";

Create a hash of hashes; via references

The following two solutions are equivalent, except for the way the look. In my opinion the second approach is clearer.

Solution

    $requiredPatches_href->{ $patch }->{ os }    = $os;
$requiredPatches_href->{ $patch }->{ arch } = $arch;
$requiredPatches_href->{ $patch }->{ info } = $info;

Solution

    $requiredPatches_href->{ $patch } = {
os => $os,
arch => $arch,
info => $info,
};

Function to build a hash of hashes; return a reference

Solution

    sub foo
{
my ( $login, $p, $uid, $gid, $gecos, $dir, $s );
my %HoH = ();
my $file = '/etc/passwd';
open( PASSWD, "< $file" ) or die "Can't open $file : $!";
while( ) {
( $login, $p, $uid, $gid, $gecos, $dir, $s ) = split( ':' );
$HoH{ $login }{ 'uid' } = $uid;
$HoH{ $login }{ 'gid' } = $gid;
$HoH{ $login }{ 'dir' } = $dir;
}
close PASSWD;
return \%HoH;
}

Access and print a reference to a hash of hashes

Solution

    my $rHoH = foo();
my( $uid, $gid, $dir );
for my $login ( keys %$rHoH ) {
$uid = $rHoH->{ $login }->{ 'uid' }; # method 1 most readable
$gid = ${ $rHoH->{ $login } }{ 'gid' }; # method 2
$dir = ${ ${ $rHoH }{ $login } }{ 'dir' }; # method 3 least readable
print "uid: $uid, gid: $gid, dir, $dir.\n";
}

Solution

    my $rHoH = foo();
for my $k1 ( sort keys %$rHoH ) {
print "k1: $k1\n";
for my $k2 ( keys %{$rHoH->{ $k1 }} ) {
print "k2: $k2 $rHoH->{ $k1 }{ $k2 }\n";
}
}

Function to build a hash of hashes of hashes; return a reference

Solution

    sub foo
{
my %HoHoH = ();
while( ... ) {
if( /LOCATION:/ ) {
...
} elsif( /MODULE:/ ) {
$HoHoH{ $loc }{ $module_type }{ MODULE_NAME } = $module_name;
} elsif( $ARGS_ALLOWED ) {
$HoHoH{ $loc }{ $module_type }{ $arg_name } = $arg_value;
}
}
return \%HoHoH;
}

Access and print a reference to a hash of hashes of hashes

Solution

    my $rHoHoH = foo();
for my $k1 ( sort keys %$rHoHoH ) {
print "$k1\n";
for my $k2 ( sort keys %{$rHoHoH->{ $k1 }} ) {
print "\t$k2\n";
for my $k3 ( sort keys %{$rHoHoH->{ $k1 }->{ $k2 }} ) {
print "\t\t$k3 => $rHoHoH->{ $k1 }->{ $k2 }->{ $k3 }\n";
}
}
}

Print the keys and values of a hash, given a hash reference

Solution

    while( my ($k, $v) = each %$hash_ref ) {
print "key: $k, value: $v.\n";
}

Determine whether a hash value exists, is defined, or is true

Solution

    print "Value EXISTS, but may be undefined.\n" if exists  $hash{ $key };
print "Value is DEFINED, but may be false.\n" if defined $hash{ $key };
print "Value is TRUE at hash key $key.\n" if $hash{ $key };

Example

Let's say we execute an sql query where some of the resulting values may be NULL. Before attempting to use any of the values we should first check whether they are defined, as in the following code. Note that the subroutine sql_fetch_hashref() takes care of connecting to the database, preparing the statement, executing it, and returning the resulting row as a hash reference using DBI's fetchrow_hashref() method.

    my $answers = 'a,b,c,d,e';
my $sql = "select max_time, $answers from questions " .
'where question_number=?';
my $hash_ref = sql_fetch_hashref( $sql, $q );
my @answers = split ',', $answers;
my $max_time = $hash_ref->{max_time} || '60';
my $hash_ref_ans;
for my $letter ( @answers ) {
$hash_ref_ans->{ $letter } = $hash_ref->{ $letter }
if defined $hash_ref->{ $letter };
}

The for loop made a new hash of only defined key/value pairs.

2009年5月27日星期三

perl的引用和数据结构

===============================

自己写程序真是菜,到现在才完完全全理解了perl的引用下面的笔记,先发引用
每个人都需要复合的数据结构,在Perl中我们的办法是通过'引用'来实现。这里有四个重要的操作'引用'的规则:两个方法用于创建'引用',另外两个用于使用'引用'。 一旦掌握了这些规则,你可以用'引用'来处理很多重要的事情。

创建引用

方法1(\大法)
$aref = \@array; #$aref保存着指向@array的引用
$href = \@hash; #$href保存着指向%hash的引用

方法2(括号大法)
[ITEMS] 创建一个新的匿名数组,并返回一个数组的引用
{ITEMS} 创建一个新的匿名哈希,并返回一个哈希的引用

$aref = [ 1, "foo", undef, 13 ]; # $aref 保存了这个数组的'引用'
$href = { APR =>; 4, AUG =>; 8 }; # $href 保存了这个哈希的'引用'

分别和总结
# 这里: $aref = [ 1, 2, 3 ]; 和后面一样: @array = (1, 2, 3); $aref = \@array;
前面一种方法是后面两行的缩写,除了第一种方法没有创建一个多余的数组变量@array。
如果你只是编写符号 [], 你将得到一个新的、空匿名数组。如果你使用符号 {},就能得到一个新的、空匿名哈希。

使用引用
方法1(简单,不容易错反正给原来用数组或哈希的地方替换就好了,在输出时也可以)
始终使用一个有大括号的数组'引用',来替换一个数组的名字,如@{$aref}代替@array.

数组
对数组的操作 对引用操作
@a @{$aref} 一个数组
reverse @a reverse @{$aref} 对一个数组做倒序排序
$a[3] ${$aref}[3] 数组中的一个成员
$a[3] = 17; ${$aref}[3] = 17 对一个成员赋值
哈希的'引用'和数组的'引用'完全一样
对h的操作 对引用的操作
%h %{$href} 一个哈希
keys %h keys %{$href} 从哈希中将键取出来
$h{'red'} ${$href}{'red'} 哈希中的一个成员
$h{'red'} = 17 ${$href}{'red'} = 17 对一个成员赋值

方法2(上面的方法好用,但不方便读,下面会方便些)
${$aref}[3] 可以写成 $aref->[3]. #注$aref->[3]不等同$aref[3],前面的$aref->表示的其实是@aref,后面只是一个标量
${$href}{red} 可以写成 $href->{red}. #同上

箭头符号规则
在两个下标之间的箭头是可选的。 $a[1][2]来代替$a[1]->[2]
使用方法1 中,当大括号里面是一个象$aref这样的标量变量时,你可以省略掉这个大括号。例如, @$aref 和@{$aref}是一样.

perl中容易出问题和要注意的地方
下面的操作不会copy '引用'指向的数组:
$aref2 = $aref1;
你将得到两个'引用',它们都指向同一个数组。如果你修改了$aref1->;[23]的值,那么你查看变量$aref2->;[23]时,它也相应地变了。
所以,如果你要copy这个数组,你需要这样
$aref2 = [@{$aref1}];
使用符号 [...] 来创建一个新的匿名数组, 而且这个新的数组的'引用'被赋值给了$aref2 。 这个新的数组用'引用'$aref1所指向的数组的内容来初始化。
同样的,要copy一个匿名哈希,你需要这样
$href2 = {%{$href1}};

2009年5月22日星期五

vim---关于程序编写

set
zf-zo-zc-zi-zn-zN-zr-zm
set foldopen[close]=all,&
set foldmethod=indent
set foldlevel=0--
set foldcolumn=4 创建显示区


:mkview--创建视图区
loadview--


c+T
c+]
:tags 显示
:tag跳转到最后
:tfirst
:[count]tprevious
:[count]tnext
:tlast
:tnext
:tag /block
:tag write_
:ptag-
:pclose-预览函数定义,打开关闭
:pedit
:psearch


%
[#
#]--跳到if-endif结构的开头,结尾
[{-
]}--跳到大括号结构开头,结尾
[]--
]]--上一函数结尾,下一函数开始
[(--])-------
[/--]/--只对 /* 注释有效
[I--查找所有使用此定义的行
[或者[c-I -- 跳到第一次遇到的行C-O跳回来
[i 只列出第一个匹配的
]I 只列出当前光标之后的匹配项
]i 只列出当前光标之后的第一个匹配项
gD-局部搜索变量=[I 在局部使用
gd-查找当前函数

2009年5月12日星期二

Perl-内容提示

Perl通用法则:如果去掉括号不影响程序的话就可以去掉

标量-1234566==1_234_567,为了便于阅读

字符串-
1,可以包含任意字符,可以把图片,编译好的程序放入字符串中修改

2,没有c中结束的Null

3,单引号中只有反斜杠和单引号需要转义

4,5x4<==> "5"x4<==>"5555"

5,数字和字符串自动转换,字符串转成数字时取第一个数字,其后忽略“44dddee33”*2=88
字符串如无数字转换成0. 字符串中0开头不表示非十进制数字,必须使用hex或org
"Z".3*5="Z15"

6,print "kkk",3*4,"\n"; -是被允许的

布尔值-Perl无布尔值,0=""=undef="0"=false,其余所有都为真. defined 函数可以查询undef值

数组-
1,如果下标超出,返回undef

2,$#ArrayName=得到最后数组元素下标

3,@表引用这整个数组-@rocks=qw/i am a student/; 对起数组前四个赋值

4,foreach $element(@menge)中,$element不是数组元素拷贝,而是其本身

5,sort 不会修改数组本身,需要重新写入 @kk=sort @kk;

6,sort sort_func @array;利用排序函数给数组排序,排序函数中$a,$b值不需要赋值,可以使用三向比较符 "<=>",返回-1,0,1

7,grep 过滤数组值

qw-
1,当作单引号,并忽略空格,分界符可以是任意符号,(),[],{},!!,##............但是要相应转义

2,($fred, $barney) = qw ;只给前两个值,其余舍去

context-
1,@backwards = reverse qw / yabba dabba doo /;
#返回 doo, dabba, yabba
$backwards = reverse qw/ yabba dabba doo /;
#返回 oodabbadabbay

2,@wilma = undef;由于 undef 是一个标量值,将 undef 赋给数组不会清空数组。

文件和目录-
1,opendir/open,readline/readdir,closedir/close

2,readdir得到文件名而不是全路径-***,如果测试文件,需要变成全路径,否则为测试当前路径下文件***

3,unlink,删除文件,其余还有symlink,readlink,mkdir,rmdir,chown,utaimi(改变时间戳)

执行shell-
1,system,exec

2,反引号捕获输出,例如 $now=`date`

环境变量-%ENV{"变量名"}

2009年5月4日星期一

Linux-Date--显示日期

date yesterday 显示昨天日期

2009年5月2日星期六

Latex-改变行距

1, 改变局部行距
\usepackage{setspace}
\begin{document}
\begin{spacing}{2.0}
%%行间距变为double-space

\begin{spacing}{1.0}
%%行间距变为single-space
\end{spacing}

\end{spacing}
\end{document}
2,對於整份文件正文的行距我們可以在全域區中使用
\linespread{1.5}
來設定其行距。

但是有時候 某段文章/表格或 minipage 需要有不同的行距時,要怎麼做比較好呢?試了幾種方法後發現這樣比較快。

{\renewcommand\baselinestretch{0.8}\selectfont
要改變行距的部分
\par}
3,设置array的列间距为1pt:
\setlength{\arraycolsep}{1pt}

改变array的行间距为原来的1.5倍:
\renewcommand{\arraystretch}{1.5}