prime_main v0.3.7

October 26th, 2005 by 1e0n

都忘了对以前版本有什么修改了,加入write_db()作为连接。

#!/usr/bin/perl -w
#use strict;
# file:prime_main
# main program of prime_project.
# by:leon 05/10/26 v0.3.7

use Socket;
use IO::Handle;
use read_write_db qw(read_db write_db);
use cal_prime qw(cal_prime_by_step);

# Bidirectional communication using socketpair
socketpair(CHILD, PARENT, AF_UNIX, SOCK_STREAM, PF_UNSPEC) or  die "socketpair: $!";
CHILD->autoflush(1);
PARENT->autoflush(1);

unless ($pid = fork) {
    # This is Child,for calculate prime
    die "cannot fork: $!" unless defined $pid;
    close CHILD;
    print "CHILD PID:$$\n";

    # Child ignore "ctrl+c"
    $SIG{INT} = ‘IGNORE’;

    # Read date from database for prepare calculate
    local (@prime_n_array,$prime_step_id);
    read_db(*prime_n_array,*prime_step_id);
    #print "@prime_n_array,$prime_step_id\n";

    while (1) {
        print PARENT "go_on?\n";
        chomp($line = <PARENT>);

        if ($line eq "go_on") {
            # Parent didn’t catch "ctrl+c" so we go on next step calculate
            print "go on next step calculate\n";

            #$i = 0;
            #while (++$i<3) {
            cal_prime_by_step(*prime_n_array,*prime_step_id);
           write_db();
            #}
            #last;
        } elsif ($line eq "exit") {
            # Parent catch "ctrl+c" so we stop
            print "Child do something before exit\n";
            write_db();
            exit;
        } else {
            # For Extensions
            print "Child:I don’t understand What Parent say.\n";
            exit;
        }
    }

    print "CHILD end\n";

    close PARENT;
    exit;
} else {
    # This is Parent,for control Child
    close PARENT;

    # Catch ctrl+c,but don’t exit directly.Parent send a msg
    # to Child then exit after Child finish ending work
    $SIG{INT} = sub {$int_count++};

    while (chomp($line = <CHILD>)) {
        if ($int_count) {
            print CHILD "exit\n";
            last;    #jump out of "while"
        }

        if ($line eq "go_on?") {
            print CHILD "go_on\n";
        } else {
            # For Extensions
            print "Parent:I don’t understand What Child say.\n";
        }
    }

    print "Parent going to exit.\n";
    close CHILD;
    waitpid($pid,0);
}

cal_prime.pm v0.3.4

October 26th, 2005 by 1e0n

good news!程序到现在已经整个能工作了!
只是差一步把write_db写出来!
这个cal_prime版本真的是比原来简单了好些,只用了很短的代码:)
到现在整个project用了195行代码。

#!/usr/bin/perl
# file:cal_prime.pm
# calculate prime.
# by:1e0n 05/10/26 v0.3.4

package cal_prime;
require Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = qw(cal_prime_by_step);

sub cal_prime_by_step {
    # Use Typeglob to make a efficient prarmeter passing
    local (*cp_prime_n_array,*cp_prime_step_id) = @_;
    $prime_n_last = $cp_prime_n_array[-1];
    my $prime_id_count = @cp_prime_n_array-1;
    #print "prime_n_array:        @cp_prime_n_array\n";
    #print "last prime:        $prime_n_last\n";
    #print "count:            $prime_id_count\n";
    #print "sqrt_of_prime_id:    $cp_prime_step_id\n";
    #print "sqrt_of_prime_n:    $cp_prime_n_array[$cp_prime_step_id]\n";

    # Use Typeglob to change name
    local *prime = *cp_prime_n_array;
    local *last_num_to_cal = *prime_n_last;

    # We can use "do{something;}while();" function in the follow code
    # but it’s unclear
    $last_num_to_cal += 2;
    $cp_prime_step_id++;

    # Go into a calculate prime step
    while ($last_num_to_cal < $prime[$cp_prime_step_id]**2) {
        $if_prime = 1;
        #print "checking $last_num_to_cal with step $cp_prime_step_id\n";

        for (1..$cp_prime_step_id) {
            if ($last_num_to_cal % $prime[$_] == 0) {
                $if_prime = 0;
                last;
            }
        }

        if ($if_prime) {
            $prime[++$prime_id_count] = $last_num_to_cal;
            print "$prime_id_count prime is $last_num_to_cal\n";
            #print $last_num_to_cal."    ";
        }

        $last_num_to_cal += 2;
    }
}

1;

prime_main v0.3.6

October 26th, 2005 by 1e0n

继续完善程序和修正了一些小错误。
其实现在cal_prime_by_step并不难写了。

#!/usr/bin/perl -w
#use strict;
# file:prime_main
# main program of prime_project.
# by:leon 05/10/26 v0.3.6

use Socket;
use IO::Handle;
use read_write_db qw(read_db write_db);
use cal_prime qw(cal_prime_by_step);

# Bidirectional communication using socketpair
socketpair(CHILD, PARENT, AF_UNIX, SOCK_STREAM, PF_UNSPEC) or  die "socketpair: $!";
CHILD->autoflush(1);
PARENT->autoflush(1);

unless ($pid = fork) {
    # This is Child,for calculate prime
    die "cannot fork: $!" unless defined $pid;
    close CHILD;
    print "CHILD PID:$$\n";

    # Child ignore "ctrl+c"
    $SIG{INT} = ‘IGNORE’;

    # Read date from database for prepare calculate
    local (@prime_n_array,$prime_step_id);
    read_db(*prime_n_array,*prime_step_id);
    #print "@prime_n_array,$prime_step_id\n";

    while (1) {
        print PARENT "go_on?\n";
        chomp($line = <PARENT>);

        if ($line eq "go_on") {
            # Parent didn’t catch "ctrl+c" so we go on next step calculate
            print "go on next step calculate\n";
            cal_prime_by_step(*prime_n_array,*prime_step_id);
        } elsif ($line eq "exit") {
            # Parent catch "ctrl+c" so we stop
            print "Child do something before exit\n";
            exit;
        } else {
            # For Extensions
            print "Child:I don’t understand What Parent say.\n";
            exit;

        }
    }

    print "CHILD end\n";

    close PARENT;
    exit;
} else {
    # This is Parent,for control Child
    close PARENT;

    # Catch ctrl+c,but don’t exit directly.Parent send a msg
    # to Child then exit after Child finish ending work
    $SIG{INT} = sub {$int_count++};

    while (chomp($line = <CHILD>)) {
        if ($int_count) {
            print CHILD "exit\n";
            last;    #jump out of "while"
        }

        if ($line eq "go_on?") {
            print CHILD "go_on\n";
        } else {
            # For Extensions
            print "Parent:I don’t understand What Child say.\n";
        }
    }

    print "Parent going to exit.\n";
    close CHILD;
    waitpid($pid,0);
}

read_write_db.pm v0.3.4

October 26th, 2005 by 1e0n

统一下参量名,另外对应修改了列表名。

#!/usr/bin/perl
# file:read_write_db.pm
# read mysql database into hashref or write back hashref to database.
# by:1e0n 05/10/26 v0.3.4

package read_write_db;
require Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = qw(read_db write_db);

use DBI();
use read_conf qw($user $pwd);

sub read_db {
    # Use Typeglob to make a efficient prarmeter passing
    local (*cp_prime_n_array,*cp_prime_step_id) = @_;
    my $n;

    # Connect to the database.
    my $dbh = DBI->connect("DBI:mysql:database=prime_db;host=localhost",
                            $user,$pwd,
                            {’RaiseError’ => 1});

    # pick out all prime to ref && sqrt_of_prime_id to ref
    my $prime_n_ref = $dbh->selectall_arrayref("SELECT prime_n FROM prime_table");
    my $prime_step_id_ref = $dbh->selectrow_arrayref("SELECT MAX(prime_step_id) FROM prime_table");

    # copy prime to array "copy_prime",$cp_prime_n_array[0] is no use but we let it equal 1.
    # we start from $cp_prime_n_array[1] = 2 which mean the first prime is 2.
    @cp_prime_n_array = (1);
    foreach (@$prime_n_ref) {
        $cp_prime_n_array[++$n]=$_->[0];
    }

   $cp_prime_step_id = $prime_step_id_ref->[0];

    #print "列数: $#{$ref}+1 行数?: $#{$ref->[0]}+1\n";
    #print "@$ref[0]->[1]\n";

    # after reading data disconnect mysql
    $dbh -> disconnect();
}

sub write_db {
}

1;

init_mysql_database v0.3.7

October 26th, 2005 by 1e0n

这程序一直改动不多,只是改了下列表名。

#!/usr/bin/perl -w
# file:init_mysql_database
# Init mysql database.
# by:1e0n 05/10/25-v0.3.7
use strict;
use DBI();
use read_conf qw($user $pwd);

# Connect to the database.
print "init_mysql: Connect to the database\n";
my $dbh = DBI->connect("DBI:mysql:database=prime_db;host=localhost",
                       $user,
                          $pwd,
                          {’PrintError’ => 0})
        or die "Fail: Maybe you havn’t insert prime_db to mysql?\n      See prime.conf\n";

# Drop table ‘prime_table’.
$dbh->do("DROP TABLE prime_table");

# Create a new table ‘prime_table’.
# This’s the table we store the prime series.
print "init_mysql: Init table\n";
$dbh->do("CREATE TABLE prime_table (id                    INTEGER,
                                    prime_n                INTEGER,
                                    prime_step_id        INTEGER,
                                    prime_step_n        INTEGER)");

# Insert init data into ‘prime_table’,that’s:
# +—–+——-+————-+————+
# | id  |prime_n|prime_step_id|prime_step_n|
# +—–+——-+————-+————+
# |  1  |   2   |      1      |      1     | first prime is 2,and sqrt(2) is 1
# |  2  |   3   |      1      |      1     | second prime is 3,and sqrt(3) is 1
# +—–+——-+————-+————+
print "init_mysql: Init data\n";
$dbh->do("INSERT INTO prime_table VALUES(1,2,1,1)");
$dbh->do("INSERT INTO prime_table VALUES(2,3,1,1)");

# Now all finish.
# Disconnect from the database.
print "init_mysql: Now database is ready\n";
$dbh->disconnect();

prime_main v0.3.3

October 26th, 2005 by 1e0n

依照prime_project的v0.3原型写的prime_main,已经工作的很好,简单明了!!
各个模块功能独立,专一,这个主程序框架应该不用再改进了。
下面开始写模块……又要改参量名了:)

#!/usr/bin/perl -w
#use strict;
# file:prime_main
# main program of prime_project.
# by:leon 05/10/26 v0.3.3

use Socket;
use IO::Handle;
use read_write_db qw(read_db write_db);
use cal_prime qw(cal_prime_by_step exit_cal_prime);

# Bidirectional communication using socketpair
socketpair(CHILD, PARENT, AF_UNIX, SOCK_STREAM, PF_UNSPEC) or  die "socketpair: $!";
CHILD->autoflush(1);
PARENT->autoflush(1);

unless ($pid = fork) {
    # This is Child,for calculate prime
    die "cannot fork: $!" unless defined $pid;
    close CHILD;
    print "CHILD PID:$$\n";

    # Child ignore "ctrl+c"
    $SIG{INT} = ‘IGNORE’;

    # Read date from database for prepare calculate
    read_db(*prime_n_array,*sqrt_of_prime_id);
    #print "@prime_n_array,$sqrt_of_prime_id\n";

    while (1) {
        print PARENT "go_on?\n";
        chomp($line = <PARENT>);

        if ($line eq "go_on") {
            # Parent didn’t catch "ctrl+c" so we go on next step calculate
            cal_prime_by_step(*prime_n_array,*sqrt_of_prime_id);
        } elsif ($line eq "exit") {
            # Parent catch "ctrl+c" so we stop
            print "Child do something before exit\n";
            exit;
        } else {
            # For Extensions
        }
    }

    print "CHILD end\n";

    close PARENT;
    exit;
} else {
    # This is Parent,for control Child
    close PARENT;

    # Catch ctrl+c,but don’t exit directly.Parent send a msg
    # to Child then exit after Child finish ending work
    $SIG{INT} = sub {$int_count++};

    while (chomp($line = <CHILD>)) {
        if ($int_count) {
            print CHILD "exit\n";
            last;    #jump out of "while"
        }

        if ($line eq "go_on?") {
            print CHILD "Go to sleep,baby\n";
        } else {
            # For Extensions
        }
    }

    print "Parent going to exit.\n";
    close CHILD;
    waitpid($pid,0);
}

完成了v0.3的处理模型。

October 26th, 2005 by 1e0n

这只是个prime_project主程序信号原型的测试程序,我假设子进程是“儿子”,父进程是“爸爸”。
有兴趣可以试试,这是这个程序我机子上子进程和父进程的对话:

# ./pipe6
child cry: `Dad,can I sleep?’                    #儿子每3秒向父亲哭一次:我可以睡觉吗
Dad say: `Go to sleep,baby’                    #然后老爸说“去睡吧”
child cry: `Dad,can I sleep?’                    #儿子睡了3秒后又哭了…
Dad say: `Go to sleep,baby’                  #老爸没收到我的中断,继续…
Dad say: `we have no time,baby’          #其实应该儿子问先的,因为有中断,然后
baby die                                                       #老爸就告诉儿子我们没时间了。
child cry: `Dad,can I sleep?’                    #然后老爸和儿子就一起死了……残忍……
断开的管道

#!/usr/bin/perl -w
# pipe6 - bidirectional communication using socketpair
#   "the best ones always go both ways"

use Socket;
use IO::Handle;
# We say AF_UNIX because although *_LOCAL is the
# POSIX 1003.1g form of the constant, many machines
# still don’t have it.
socketpair(CHILD, PARENT, AF_UNIX, SOCK_STREAM, PF_UNSPEC)
    or  die "socketpair: $!";

CHILD->autoflush(1);
PARENT->autoflush(1);
#$SIG{INT} = sub {$int_count++};

if ($pid = fork) {
    # I am parent
    close PARENT;

    #if ($int_count) {
    #    print CHILD "we have no time,baby\n";
    #}

    $SIG{INT} = sub {print CHILD "we have no time,baby\n";};

    # Wait until child cry.
    while (chomp($line = <CHILD>)) {
        print "child cry: `$line’\n";
        print CHILD "Go to sleep,baby\n";
    }

    print "why i going to exit?\n";
    close CHILD;
    #waitpid($pid,0);
} else {
    $| = 1;

    # I am child
    die "cannot fork: $!" unless defined $pid;
    $SIG{INT} = ‘IGNORE’;
    close CHILD;

    while (1) {
        print PARENT "Dad,can I sleep?\n";
        chomp($line = <PARENT>);
        print "Dad say: `$line’\n";

        if ($line eq "we have no time,baby") {
            print "baby die\n";
            exit;
        }
        sleep 3;
    }

    close PARENT;
    exit;
}

going to prime_project v0.3

October 26th, 2005 by 1e0n

发现前面的版本还是陷入了一个开发黑洞。

在处理中断信号ctrl+c的问题上掉入了陷阱,我想在子进程中捕捉信号并在捕捉到信号时处理剩下的任务–把任务执行到安全过程时中断并做结尾工作,结果捕捉到的同时子进程的任务也自动中断了!

而且在繁杂的测试中失去了模块功能专一性–我试图在模块中处理信号,而这应该是主程序的工作。

我又试图通过一个参量传递中断状态–但是父进程和子进程的资源是完全独立的,这样参量无法传递,虽然在cookbook上看到有在进程间共享参量的方法,但是这无疑增加了复杂性。

现在终于想到解决方法,就是重写cal_prime,只是重写一点点,这样我把cal_prime做成个step by step的计算过程,cal_prime计算一段时间后退出回到主程序,然后主程序查看信号状态,然后决定是继续下一个step的计算还是做收尾工作退出。

这里需要子进程和父进程的对话–父进程捕捉信号,而子进程忽略信号,注意,这点很重要!

父进程做监视中断的动作,当父进程捕捉到中断时不会立即中断,而是跳入一个处理中断的sub,这个sub再告诉子进程“准备收工”了,子进程因为忽略了中断还会继续计算prime或者查看中断状态,当计算完那个step的工作后查看中断状态–“哦,父进程告诉我收工了”,于是子进程开始做收尾工作。

而在之前的版本中我是把cal_prime做成一个“阻塞”的过程模块,这样它就没时间查看中断状态。

所以现在的工作是让子进程和父进程沟通会话,这个的好处不仅仅体现在传递中断状态,它的前瞻性使得程序功能以后有更大的扩展空间。

我在这里选择了牺牲一点点的性能,但是换来程序的自由度和透明性。

cal_prime.pm v0.2.2

October 25th, 2005 by 1e0n

接口已经完成,虽然完成的不太优雅……
不过在处理进程的时候出现了问题,产生了2个父进程和2个子进程,而且不能用ctrl+c关闭,这是个很奇怪的问题。
不过这依旧是个很值得记录的版本。
接下来处理进程问题。

#!/usr/bin/perl
# file:cal_prime.pm
# calculate prime.
# by:1e0n 05/10/25 v0.2.2

package cal_prime;
require Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = qw(cal_prime);

sub cal_prime {
    #—————GET ARRAY————–#

    # Use Typeglob to make a efficient prarmeter passing
    local (*cp_prime_n_array,*cp_sqrt_of_prime_id) = @_;
    $prime_n_last = $cp_prime_n_array[-1];
    my $prime_id_count = @cp_prime_n_array-1;
    print "prime_n_array:        @cp_prime_n_array\n";
    print "last prime:        $prime_n_last\n";
    print "count:            $prime_id_count\n";
    print "sqrt_of_prime_id:    $cp_sqrt_of_prime_id\n";
    print "sqrt_of_prime_n:    $cp_prime_n_array[$cp_sqrt_of_prime_id]\n";

    #—————CAL PRIME—————#
    local *prime = *cp_prime_n_array;
    local *prime_flag = *cp_sqrt_of_prime_id;
    local *num = *prime_n_last;

    while (1) {            #calculate prime until get $SIG{INT}(ctrl+c)
        $num++;
        $if_prime = 1;

        if ($prime[$prime_flag+1] * $prime[$prime_flag+1] == $num) {
            $prime_flag++;
            #print $prime_last." ".$prime_flag." ".$prime[$prime_flag]." ".$num."\n";
            next;               #so $num already is not a prime,just go next
        }

        for (1..$prime_flag) {
            if ($num % $prime[$_] == 0) {
                $if_prime = 0;
                last;
            }
        }

        if ($if_prime) {
            $prime[++$prime_last] = $num;
            #print $prime_last." ".$num."\n";
            print $num."    ";
        }
    }
}

read_write_db.pm v0.2.3

October 25th, 2005 by 1e0n

原来的@prime是从$prime[0]=2开始的,现在改为从$prime[1]=2开始。
一个是为了和cal_prime的数据连接,另一个也是变得更加有意义:第1个prime是2,而不是第0个!
这个个非常棒的改进~

#!/usr/bin/perl
# file:read_write_db.pm
# read mysql database into hashref or write back hashref to database.
# by:1e0n 05/10/25 v0.2.3

package read_write_db;
require Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = qw(read_db write_db);

use DBI();
use read_conf qw($user $pwd);

sub read_db {
    # Use Typeglob to make a efficient prarmeter passing
    local (*cp_prime_n_array,*cp_sqrt_of_prime_id) = @_;

    # Connect to the database.
    my $dbh = DBI->connect("DBI:mysql:database=prime_db;host=localhost",
                            $user,$pwd,
                            {’RaiseError’ => 1});

    # pick out all prime to ref && sqrt_of_prime_id to ref
    my $prime_n_ref = $dbh->selectall_arrayref("SELECT prime_n FROM prime_table");
    my $sqrt_of_prime_id_ref = $dbh->selectrow_arrayref("SELECT MAX(sqrt_of_prime_id) FROM prime_table");

    # copy prime to array "copy_prime",$cp_prime_n_array[0] is no use but we let it equal 1.
    # we start from $cp_prime_n_array[1] = 2 which mean the first prime is 2.
    @cp_prime_n_array = (1);
    my $n = 1;

    foreach (@$prime_n_ref) {
        $cp_prime_n_array[$n++]=$_->[0];
    }

    $cp_sqrt_of_prime_id = $sqrt_of_prime_id_ref->[0];

    #print "prime_n_array: @cp_prime_n_array\n";
    #print "sqrt_prime_id: $sqrt_of_prime_id_ref->[0]\n";
    #print "列数: $#{$ref}+1 行数?: $#{$ref->[0]}+1\n";
    #print "@$ref[0]->[1]\n";

    # after reading data disconnect mysql
    $dbh -> disconnect();

}

sub write_db {
}

1;