莊周夢蝶

          生活、程序、未來
             :: 首頁 ::  ::  :: 聚合  :: 管理

              學習和使用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 閱讀(1664) | 評論 (2)編輯 收藏

              最近重新拿起《工作流管理-模型、方法和系統》,需要一個Petri網畫圖、分析的工具,google一把,在sourceforge上找到PIPE2項目。按它的描述是:Platform Independent Petri Net Editor 2。看了下源碼是用swing寫的。已經基本滿足我的要求了。
          項目地址:http://pipe2.sourceforge.net/

          下圖是對書中習題七的過程定義




          posted @ 2007-09-05 16:51 dennis 閱讀(3668) | 評論 (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 閱讀(699) | 評論 (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 閱讀(1811) | 評論 (0)編輯 收藏

              又一個同事決定辭職,長期出差讓他受不了。我也猶豫了,來這家公司一年了,合同簽到明年春節后。其實前段時間有公司聯系過我,因為女朋友的關系,我并不是很想現在換工作就拒絕了。可現在項目即將轉入維護階段,近段時間內公司似乎也沒有新的項目,而我也需要更多項目鍛煉的機會,是需要好好考慮下了。

          posted @ 2007-09-03 14:09 dennis 閱讀(371) | 評論 (0)編輯 收藏

              等待國米比賽還有一個小時,剛看完一部電影《導火線》,不是《盜火線》。甄子丹的新片,實打實的功夫,打的精彩異常,故事很老套,不過導演安排的也還算緊湊,整部片子看下來一直神經緊繃,也許也是因為音樂的感染。甄子丹在戲里的打斗風格有很大改變,出現了非常多精彩的柔術技法,融合了自由搏擊、泰拳、拳擊的打斗風格很有看頭,已經沒有多少傳統武術的痕跡了,大反派的pose倒有點像黃師傅的經典動作。聯想到今年CCTV5的武林大會,里面推來推去的街頭莽漢式打斗,將功夫電影留下來的美好印象擊的粉碎。有人說這就是當今武術的現狀,有的說上臺的都是些年輕人,功夫不到家,不管真實如何,傳統武術的勢微似乎無法避免。不過武林大會的舉辦終究是好事,希望明年能見到更多真正的技擊高手吧。
              我從小就很喜歡武術,我父親也是個功夫迷,當年《少林寺》熱映,引起了一陣學習傳統武術的高潮,我家現在還有一大堆80年代的武術期刊,我弟弟干脆被我父親送去了武校。我自己在初中得過一陣神經衰弱,后來學習了一套養身的功法,才慢慢恢復,沒耽誤了學習。傳統武術是寶貴的文化遺產,也希望后來人能一直做永恒的武俠夢。

          posted @ 2007-09-02 01:33 dennis 閱讀(313) | 評論 (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 閱讀(4454) | 評論 (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 閱讀(530) | 評論 (0)編輯 收藏

              在infoq上看到這個消息,想了解ruby的不妨從這份教程開始,初略看了下目錄,內容還是挺全的,該介紹的都介紹到了。我自己準備將Advanced ruby部分讀一下,也算是練手,想掌握任何一門編程語言,每天至少都得寫上那么幾段代碼保持“手感”,HOHO。一天一個主題,利用業余時間和工作間隙花上兩個星期就夠了。

          posted @ 2007-08-31 09:06 dennis 閱讀(282) | 評論 (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 閱讀(1973) | 評論 (0)編輯 收藏

          僅列出標題
          共56頁: First 上一頁 34 35 36 37 38 39 40 41 42 下一頁 Last 
          主站蜘蛛池模板: 嵊泗县| 大港区| 延川县| 仙桃市| 塔河县| 永善县| 齐齐哈尔市| 望江县| 治多县| 宜兰市| 繁峙县| 岱山县| 洛宁县| 渑池县| 汝城县| 安陆市| 大丰市| 西藏| 游戏| 乐都县| 金川县| 安陆市| 阳原县| 酒泉市| 商河县| 顺昌县| 洛隆县| 伊春市| 通海县| 大同县| 大新县| 新晃| 德州市| 江源县| 开远市| 达拉特旗| 黎川县| 云安县| 绵竹市| 惠来县| 连州市|