庄周梦蝶

生活、程序、未来
   :: 首页 ::  ::  :: 聚合  :: 管理

    学习和使用java有四年多了,现在却回头搞起了C,理由有三:
1、为了考试啊,我也知道高程证书含金量不怎么样,可为了督促自己再次深入学习下基础知识,考个证没坏处。

2、我想读《ruby hacking guide》,ruby是用C写的,自从看了dreamhead老大的《管窥ruby》之后,我一直有股强烈的冲动去读ruby的源码。想把冲动转成行动,不深入下C语言是不行的。有牛人将Erlang的源码都看了,尽管我觉的我这辈子还达不到那么牛,不过偶尔去探访一下神秘的代码丛林也能满足下好奇心。甚至某天去看看jvm的源码......浮云。

3、没错,我对unix/linux下的C开发充满了兴趣,对网络通讯方面也很感兴趣,况且用C语言去操纵内核实在是很有趣、很好玩的事情,在这个学习过程中也加深了对计算机底层运行原理的理解。

    终于将《c primer plus》看完,俨然发现c语言并非想象中的复杂,某种意义上还是非常简洁的,高效当然就更不用说咯。

posted @ 2007-09-07 14:37 dennis 阅读(1657) | 评论 (2)编辑 收藏

    最近重新拿起《工作流管理-模型、方法和系统》,需要一个Petri网画图、分析的工具,google一把,在sourceforge上找到PIPE2项目。按它的描述是:Platform Independent Petri Net Editor 2。看了下源码是用swing写的。已经基本满足我的要求了。
项目地址:http://pipe2.sourceforge.net/

下图是对书中习题七的过程定义




posted @ 2007-09-05 16:51 dennis 阅读(3653) | 评论 (0)编辑 收藏

    过去写的那个调用google翻译的翻译脚本,一直在用。那个版本只能处理单个单词,如果要翻译一行或者一段语句,尽管稍微修改下就可以,但失去了我想要的便利性。今天看了看TK,顺手写了个GUI版本的,采用一次请求一个线程,倒是便捷不少。在windows上,你需要到这里下载安装ActiveTcl才可以运行。
代码如下:
require 'net/http'
require 
'tk'
require 
'logger'
#设置代理
$proxy_addr='x.x.x.x'
$proxy_port
='80'
class GoogleTranslate
 
def initialize(url)
    @log 
= Logger.new("translate.log")
    @log.level 
= Logger::WARN
    @url
=url
    ph
={'padx'=>50,'pady'=>10}
    root
=TkRoot.new{ title 'google 翻译程序'}
    top
=TkFrame.new(root) {background "white"}
    
    
#checkbutton,用于选择翻译类别
    checked=TkVariable.new
    TkCheckButton.new(top) do
      text 
'cn-en'
      variable checked
      pack({
'padx'=>8,'pady'=>10})
    end  
    TkLabel.new(top){ text 
'Enter text:';pack(ph)}
    
    @text
=TkVariable.new
    @result
=TkVariable.new
    TkEntry.new(top,
'textvariable'=>@text,'width'=>40).pack(ph)
    pig_b
=TkButton.new(top){text '翻译';pack ph}
    
#翻译按钮事件
    pig_b.command{ translate(checked.value) }
    
    TkLabel.new(top){ text 
'Translate Result:';pack(ph)}
    TkEntry.new(top,
'textvariable'=>@result,'width'=>40).pack(ph)
    pig_a
=TkButton.new(top) do
      text 
'Exit'
      pack ph
      command {exit}
    end
    top.pack(
'fill'=>'both','side'=>'top')
  end
  
def translate(checked)
    langpair
='en|zh-CN' 
    langpair
='zh-CN|en' if checked=='1'
    
#开一个新线程处理
    Thread.new do
      begin
        response
=Net::HTTP.Proxy($proxy_addr,$proxy_port).post_form(URI.parse(@url),
            {
'text'=>@text.value,'langpair'=>langpair})
        response.body 
=~ /<div id=result_box dir=ltr>(.*?)<\/div>/
        @result.value
=$1
        rescue Exception
=>e
        @log.error(e)
      end
    end
    
  end
end
GoogleTranslate.new(
"http://translate.google.com/translate_t")
Tk.mainloop


posted @ 2007-09-04 15:55 dennis 阅读(692) | 评论 (0)编辑 收藏

    当外部代码能够在活动自然完成之前,把它的状态更改为完成状态,那么这个活动被称为可取消(cancellable)。取消任务是一个很常见的需求,无论是由于用户请求还是系统错误引起的服务关闭等等原因。最简单的任务取消策略就是在线程中维持一个bool变量,在run方法中判断此变量的bool值来决定是否取消任务。显然,这个bool变量需要声明为volatile,以保持多线程环境下可见性(所谓可见性,就是当一个线程修改共享对象的某个状态变量后,另一个线程可以马上看到修改结果)。下面是一个来自《java并发编程实践》的例子:
package net.rubyeye.concurrency.chapter7;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class PrimeGenerator implements Runnable {
    
private final List<BigInteger> primes = new ArrayList<BigInteger>();

    
private volatile boolean cancelled;
   
public void run() {
        BigInteger p 
= BigInteger.ONE;
        
while (!cancelled) {
            p 
= p.nextProbablePrime();
            
synchronized (this) {
                primes.add(p);
            }
        }
    }
   
public void cancel() {
        cancelled 
= true;
    }
   
public synchronized List<BigInteger> get() {
        
return new ArrayList<BigInteger>(primes);
    }

   
public static void main(String args[]) throws InterruptedException {
        PrimeGenerator generator 
= new PrimeGenerator();
        
new Thread(generator).start();
        
try {
            TimeUnit.SECONDS.sleep(
1);
        } 
finally {
            generator.cancel();
        }
    }
}
    main中启动一个素数生成的任务,线程运行一秒就取消掉。通过线程中的cancelled变量来表征任务是否继续执行。既然是最简单的策略,那么什么是例外情况?显然,阻塞操作下(比如调用join,wait,sleep方法),这样的策略会出问题。任务因为调用这些阻塞方法而被阻塞,它将不会去检查volatile变量,导致取消操作失效。那么解决办法是什么?中断!考虑我们用BlockingQueue去保存生成的素数,BlockingQueue的put方法是阻塞的(当BlockingQueue满的时候,put操作会阻塞直到有元素被take),让我们看看不采用中断,仍然采用简单策略会出现什么情况:
package net.rubyeye.concurrency.chapter7;

import java.math.BigInteger;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

public class BrokenPrimeProducer extends Thread {
    
static int i = 1000;

    
private final BlockingQueue<BigInteger> queue;

    
private volatile boolean cancelled = false;

    BrokenPrimeProducer(BlockingQueue
<BigInteger> queue) {
        
this.queue = queue;
    }

    
public void run() {
        BigInteger p 
= BigInteger.ONE;
        
try {
            
while (!cancelled) {
                p 
= p.nextProbablePrime();
                queue.put(p);
            }
        } 
catch (InterruptedException cusumed) {
        }
    }

    
public void cancel() {
        
this.cancelled = false;
    }

    
public static void main(String args[]) throws InterruptedException {
        BlockingQueue
<BigInteger> queue = new LinkedBlockingQueue<BigInteger>(
                
10);
        BrokenPrimeProducer producer 
= new BrokenPrimeProducer(queue);
        producer.start();
        
try {
            
while (needMorePrimes())
                queue.take();
        } 
finally {
            producer.cancel();
        }
    }

    
public static boolean needMorePrimes() throws InterruptedException {
        
boolean result = true;
        i
--;
        
if (i == 0)
            result 
= false;
        
return result;
    }
}
    我们在main中通过queue.take来消费产生的素数(虽然仅仅是取出扔掉),我们只消费了1000个素数,然后尝试取消产生素数的任务,很遗憾,取消不了,因为产生素数的线程产生素数的速度大于我们消费的速度,我们在消费1000后就停止消费了,那么任务将被queue的put方法阻塞,永远也不会去判断cancelled状态变量,任务取消不了。正确的做法应当是使用中断(interrupt):
package net.rubyeye.concurrency.chapter7;

import java.math.BigInteger;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

public class PrimeProducer extends Thread {
    
static int i = 1000;

    
private final BlockingQueue<BigInteger> queue;

    
private volatile boolean cancelled = false;

    PrimeProducer(BlockingQueue
<BigInteger> queue) {
        
this.queue = queue;
    }

    
public void run() {
        BigInteger p 
= BigInteger.ONE;
        
try {
            
while (!Thread.currentThread().isInterrupted()) {
                p 
= p.nextProbablePrime();
                queue.put(p);
            }
        } 
catch (InterruptedException cusumed) {
        }
    }

    
public void cancel() {
        interrupt();
    }

    
public static void main(String args[]) throws InterruptedException {
        BlockingQueue
<BigInteger> queue = new LinkedBlockingQueue<BigInteger>(
                
10);
        PrimeProducer producer 
= new PrimeProducer(queue);
        producer.start();
        
try {
            
while (needMorePrimes())
                queue.take();
        } 
finally {
            producer.cancel();
        }
    }

    
public static boolean needMorePrimes() throws InterruptedException {
        
boolean result = true;
        i
--;
        
if (i == 0)
            result 
= false;
        
return result;
    }
}
   在run方法中,通过Thread的isInterrupted来判断interrupt status是否已经被修改,从而正确实现了任务的取消。关于interrupt,有一点需要特别说明,调用interrupt并不意味着必然停止目标线程的正在进行的工作,它仅仅是传递一个请求中断的信号给目标线程,目标线程会在下一个方便的时刻中断。而对于阻塞方法产生的InterruptedException的处理,两种选择:要么重新抛出让上层代码来处理,要么在catch块中调用Thread的interrupt来保存中断状态。除非你确定要让工作线程终止(如上所示代码),否则不要仅仅是catch而不做任务处理工作(生吞了InterruptedException),更详细可以参考这里。如果不清楚外部线程的中断策略,生搬硬套地调用interrupt可能产生不可预料的后果,可参见书中7.1.4例子。

   另外一个取消任务的方法就是采用Future来管理任务,这是JDK5引入的,用于管理任务的生命周期,处理异常等。比如调用ExecutorService的sumit方法会返回一个Future来描述任务,而Future有一个cancel方法用于取消任务。
   那么,如果任务调用了不可中断的阻塞方法,比如Socket的read、write方法,java.nio中的同步I/O,那么该怎么处理呢?简单地,关闭它们!参考下面的例子:
package net.rubyeye.concurrency.chapter7;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;

/**
 * 展示对于不可中断阻塞的取消任务 通过关闭socket引发异常来中断
 * 
 * 
@author Admin
 * 
 
*/
public abstract class ReaderThread extends Thread {
    
private final Socket socket;

    
private final InputStream in;

    
public ReaderThread(Socket socket) throws IOException {
        
this.socket = socket;
        
this.in = socket.getInputStream();
    }

    
// 重写interrupt方法
    public void interrupt() {
        
try {
            socket.close();
        } 
catch (IOException e) {
        } 
finally {
            
super.interrupt();
        }
    }

    
public void run() {
        
try {
            
byte[] buf = new byte[1024];
            
while (true) {
                
int count = in.read(buf);
                
if (count < 0)
                    
break;
                
else if (count > 0)
                    processBuff(buf, count);
            }
        } 
catch (IOException e) {
        }
    }

    
public abstract void processBuff(byte[] buf, int count);
}
    Reader线程重写了interrupt方法,其中调用了socket的close方法用于中断read方法,最后,又调用了super.interrupt(),防止当调用可中断的阻塞方法时不能正常中断。


posted @ 2007-09-03 15:50 dennis 阅读(1804) | 评论 (0)编辑 收藏

    又一个同事决定辞职,长期出差让他受不了。我也犹豫了,来这家公司一年了,合同签到明年春节后。其实前段时间有公司联系过我,因为女朋友的关系,我并不是很想现在换工作就拒绝了。可现在项目即将转入维护阶段,近段时间内公司似乎也没有新的项目,而我也需要更多项目锻炼的机会,是需要好好考虑下了。

posted @ 2007-09-03 14:09 dennis 阅读(365) | 评论 (0)编辑 收藏

    等待国米比赛还有一个小时,刚看完一部电影《导火线》,不是《盗火线》。甄子丹的新片,实打实的功夫,打的精彩异常,故事很老套,不过导演安排的也还算紧凑,整部片子看下来一直神经紧绷,也许也是因为音乐的感染。甄子丹在戏里的打斗风格有很大改变,出现了非常多精彩的柔术技法,融合了自由搏击、泰拳、拳击的打斗风格很有看头,已经没有多少传统武术的痕迹了,大反派的pose倒有点像黄师傅的经典动作。联想到今年CCTV5的武林大会,里面推来推去的街头莽汉式打斗,将功夫电影留下来的美好印象击的粉碎。有人说这就是当今武术的现状,有的说上台的都是些年轻人,功夫不到家,不管真实如何,传统武术的势微似乎无法避免。不过武林大会的举办终究是好事,希望明年能见到更多真正的技击高手吧。
    我从小就很喜欢武术,我父亲也是个功夫迷,当年《少林寺》热映,引起了一阵学习传统武术的高潮,我家现在还有一大堆80年代的武术期刊,我弟弟干脆被我父亲送去了武校。我自己在初中得过一阵神经衰弱,后来学习了一套养身的功法,才慢慢恢复,没耽误了学习。传统武术是宝贵的文化遗产,也希望后来人能一直做永恒的武侠梦。

posted @ 2007-09-02 01:33 dennis 阅读(306) | 评论 (1)编辑 收藏

一、工作流概念
1.案例(case):工作流系统的基本目的就是处理案例,保险索赔、绩效考核、抵押申请等等都是案例。每一个案例都有一个唯一的标识,案例在出现和消失之间总是处于某个特定状态,这个状态有三个元素组成:
(1)案例相关的属性,指出特定条件下案例是否被执行或者忽略
(2)已经满足的条件,说明案例的进展。
(3)案例的内容,可能是文档、文件、档案或者数据库
2.任务(task),泛指一般的工作单元,而非具体案例活动的一次具体执行(这一般称为活动),为了区分这一点,引入了工作项(work item)和活动的概念(activity)。工作项是指将要被执行的实际工作块,而活动就是指工作项的执行。

3.过程(process):过程指出了哪些任务需要被执行,以什么顺序执行。可以将过程理解为具体案例的蓝图。过程定义了案例的生命周期,每个生命周期都有start和end。

4.路由(route):决定了那些任务被执行和以何种方式执行,包括顺序、并行、选择和循环四种形式的路由

5.启动(start):触发,工作项是有一个resource来启动的,触发的形式包括:
(1)资源驱动,比如某个员工
(2)外部事件,一个JMS消息
(3)时间信号,比如凌晨2点触发某任务等等。
显然,触发是由环境而非工作流系统负责的。
二。Petri网

    Petri网是一种过程建模和分析工具,是1962年由Carl Adam Petri提出的,它有着坚实的数学基础,完全形式化的,可以将Petri网应用于工作流的建模和分析过程。

1.传统的Petri网:
 Petri网有place(库所)和transition(变迁)组成
place用于容纳token,token用以表示具体的案例,通过transition的firing(实施)来表现过程的状态转变。理解几个概念:
(1)transition enabled(变迁的就绪):当且进当transition的每一个输入place都至少有一个token的时候,变迁就绪,可以实施。
(2)transition firing(变迁的实施):变迁的从每个输入place取走一个token,并往它的每个输出place增加一个token。
看一个Petri网进行过程建模的例子:


圆圈表示place;矩形表示transition;用黑点表示token,存在于place中,这里没有表示出来,我在网上随便找的一张图,不过这里也展示了And-split、And-join、Or-split和Or-join的四种任务以及四种形式路由(从上到下依次是:顺序、并行、选择和循环)的Petri网建模。

2.高级Petri网
    传统Petri网有一些缺点,比如无法对某些活动进行有效的建模,容易变的庞大而难以理解,因此通过扩展,就可以对复杂情况用结构化、容易理解的方式建模。关注三种扩展:颜色扩展、时间扩展和层次扩展。
1.颜色扩展,为token引入颜色,用以区分同一place中的不同token,颜色其实代表了token(具体到某个案例)的属性,通过颜色扩展,我们可以为将要被消耗的token值设置了前置条件,那么变迁就绪的前提变化为:每个输入place都至少有一个token,并且满足前置条件。颜色扩展,也将产生的token与消耗的token进行了关联,产生token的值和数目将依赖于被消耗的token的值。

2.时间扩展,当需要对一个过程的预期性能进行判断时,引入了时间扩展,为token加入时间戳,只有当被消耗的token的时间戳早于当前时间,就绪的transition才可以firing,而产生的token的时间戳就等于firing的时间加上延时。通过引入时间扩展,我们将可以对类似十字路口红绿灯时间敏感的复杂过程进行建模。

3.层次扩展,过程是由一系列的place、transition、弧线和子过程组成的,为了反映这样的层次结构,适应复杂过程的建模,引入了层次扩展。

三、工作流概念到Petri网的映射

1.过程:过程是由条件和任务组成,映射到Petri网,place就是条件,而transition就是任务。条件和place都是被动元素,而任务和变迁都是主动元素。案例就是token,案例的属性通过颜色扩展来映射,token的值包含了案例的属性值。比如保险索赔案例的属性:赔额、索赔人、时间等等。

2.路由:四种路由的Petri网建模,上面的图片已经给出。简单分析下:
(1)顺序路由,对应图1,任务A和B是顺序执行的,任务B的输入是任务A的结果。通过在两个任务之间引入一个place来解决,中间的圆圈对应的place是任务B执行前的必须满足的条件,同时是任务A执行的结果。

(2)并行路由:对应图2,为了并行地执行任务B和C,引入了任务A,称为And-split,在A和B、C之间引入两个place,当A任务实施后,为两个输出place产生token,任务B和C就处于就绪状态可以实施。当B和C都实施之后,类似的实行And-join任务(任务D)合并两个任务。

(3)选择路由:图3对选择路由的建模并不正确,选择执行B或者C,那么在B和C之前引入两个新任务t11、t12和两个place(合并称为Or-split),在前一个place的token,要么实施t11,要么实施t12,假设实施t11,那么任务B将就绪,反之则任务C就绪。同样的可以建模Or-join。选择路由还根据选择的时刻划分为两类,具体不再展开。

(4)循环路由,图四的建模也不是很精确,循环也跟编程语言中的循环分为:repeate ...until...和while ...do...两种,前者至少执行一次,而后者可能不执行,

3.启动的映射:我们知道工作项是案例和准备执行的任务的组合,而活动是指一个工作项的实际执行,一旦工作项被实际执行,它就转换成活动。映射到Petri网,工作项就是就绪的变迁(enabled transition),而活动对应一个transition的firing。Petri网中的transition是“饥饿”的,一旦它们就绪,就会立刻执行,这样的变迁成为自动的。而工作流中的触发并非是自动的,它可能是资源驱动、外部信号驱动以及时间驱动的。为了建模触发,我们在变迁的上面添加符号来区分:向下的箭头表示资源驱动,信封表示外部信号驱动,而时钟表示时间驱动。

    初步了解了Petri网,确实是对工作流甚至业务过程建模的良好工具,对于利用Petri网进行过程分析,还待进一步学习。









posted @ 2007-09-01 14:55 dennis 阅读(4435) | 评论 (0)编辑 收藏

    通过stdarg.h头文件为函数提供了定义可变参数列表的能力。声明一个可变参数的函数类似:
void f1(int n,...);

其中n表示参数列表个数,而用省略号来表示未知参数列表。stdarg.h中提供了一个va_list类型,用于存放参数。一个大概的使用过程类似:
void f1(int n,...)
{
   va_list ap;
   va_start(ap,n);   //初始化参数列表
   double first=va_arg(ap,double);  //取第一个参数
   int second=va_arg(ap,int);   //取第二个参数
   ...
   va_end(ap);  //清理工作
}
看一个求和的例子:
#include<stdio.h>
#include
<stdarg.h>
double sum(int ,);
int main(void)
{
  
double s,t;
  s
=sum(3,1.1,2.2,13.3);
  t
=sum(6,1.1,2.1,13.1,4.1,5.1,6.1);
  printf(
"return value for "  \
    
"sum(3,1.1,2.2,13.3):   %g\n",s);
  printf(
"return value for " \
    
"sum(6,1.1,2.1,13.1,4.1,5.1,6.1):    %g\n",t);
  
return 0;
}
double sum(int lim,)
{
  va_list ap;
  
double total=0;
  va_start(ap,lim);
  
int i;
  
for(i=0;i<lim;i++)
      total
+=va_arg(ap,double);
  va_end(ap);
  
return total;
}

C语言对可变参数的使用还是有点麻烦,不如ruby和java简便。比如ruby中定义并使用可变参数参数:
def sum(*e)
   e.inject{|sum,i| sum+=i}
end

sum(1,2,3,4,5)=>15
  

posted @ 2007-08-31 17:06 dennis 阅读(522) | 评论 (0)编辑 收藏

    在infoq上看到这个消息,想了解ruby的不妨从这份教程开始,初略看了下目录,内容还是挺全的,该介绍的都介绍到了。我自己准备将Advanced ruby部分读一下,也算是练手,想掌握任何一门编程语言,每天至少都得写上那么几段代码保持“手感”,HOHO。一天一个主题,利用业余时间和工作间隙花上两个星期就够了。

posted @ 2007-08-31 09:06 dennis 阅读(275) | 评论 (0)编辑 收藏

    在《unix/linux编程实践》一书中的多线程web server例子,我用ab测试一下老是导致程序挂掉,报一个断开的管道的错误。搜索得知,这个错误就是一般常见的Connection   reset   by   peer。当往关闭的管道或是socket里面写东西就会产生SIGPIPE信号,而系统默认对这个信号的处理是杀死该进程,因此解决办法就是在程序中设置忽略这个信号:
#include<signal.h>
....

signal(SIGPIPE, SIG_IGN);


posted @ 2007-08-29 19:17 dennis 阅读(1959) | 评论 (0)编辑 收藏

仅列出标题
共56页: First 上一页 34 35 36 37 38 39 40 41 42 下一页 Last