2012-10-22 32 views
0

我是perl中的線程的新手。使用信號量,而在perl中調用文件

我有一個項目列表(每個項目是在一個單獨的行)的文件,我想要並行構建這些項目。 目前,每個線程:

  1. 打開文件爲「已讀」模式
  2. 節省一些項目的列表(=一些文件行)
  3. 關閉
  4. 再次 - 打開文件作爲文件「寫」模式
  5. 重寫它沒有以確保每個線程訪問的F唯一一個選擇

,該線ile,即時嘗試使用信號量。

出於某種原因,線程collisons發生,我無法弄清楚我做錯了什麼。

我可以看到(在我的「報告」中也得到了每個版本的當前時間) 不同的線程從「共享」文件中選擇相同的項目(它只會在一段時間內發生,但仍然.. )

我甚至不確定如果我的$信號量decleration是合法的「我的」變量。

任何幫助將得到真正的讚賞!

謝謝。


這裏是我的代碼的一部分:

my $semaphore = Thread::semaphore->new() ; 

sub build_from_targets_list{ 

    #... 
    open(REPORT, "+>$REPORT_tmp"); # Open for output 
    #.... 
    @threads =(); 


    for ($i = 0; $i < $number_of_cores; $i++){ 
     my $thr = threads->new(\&compile_process, $i,*REPORT); 
     push @threads, $thr; 
    } 

    $_->join for @threads; 
    close (REPORT); 
} 
### Some stuff.. 


sub compile_process{ 

    *REPORT = shift(@_); 
    #... 

    while (1){ 
     $semaphore->down(); 
     open (DATA_FILE, $shared_file); 
     flock(DATA_FILE, 2); 
     while ($record = <DATA_FILE>) { 
      chomp($record); 
      push(@temp_target_list,$record);  
     } 


     # ... choose some lines (=projects)... 
     # remove the projects that should be built by this thread: 
     for ($k = 0; $k < $num_of_targets_in_project; $k++){    
      shift(@temp_target_list); 

     } 

     close(DATA_FILE);  
     open (REWRITE,">$shared_file"); 

     flock(REWRITE, 2); 

     seek(REWRITE, 0, 0); 
     foreach $temp_target (@temp_target_list){ 

      print REWRITE "$temp_target\n"; 

     } 

     close (REWRITE); 

     ## ... BUILD selected projects... 

     $semaphore->up(); 
     } 
} 

回答

1

首先,你是如何處理的文件的一些基本的清理工作。如果它是一個簡單的文件問題,那麼在嘗試調試線程問題時沒有意義。

必須檢查任何文件命令(打開,關閉,聚集,尋找等)是否成功。可以在那裏貼一些or dieuse autodie

其次是使用硬編碼常數的雞羣。這些是依賴於系統的,並且很難記住哪種模式2。 Fcntl提供了常量。

您正在打開數據文件以使用獨佔鎖(2通常是獨佔鎖)進行讀取。這應該可能是一個共享鎖。這不會導致問題,但它會導致您的線程不必要地阻塞。

最後,使用詞法文件句柄代替全局範圍的glob。這減少了機會

作爲一個附註,seek $fh, 0, 0打開文件寫入後是不必要的。查找常量和羣集一樣,使用Fcntl獲取常量。

一個額外的錯誤是,你傳遞$i, *REPORTcompile_process認爲*REPORT是第一個參數。再次使用全局文件句柄意味着傳遞它是多餘的,使用詞法文件句柄。

現在已經不存在了,您的基本算法似乎有缺陷。 compile_process每個線程讀取整個數據文件到線程本地數組@temp_target_list,將某些本地數組移出並寫出其餘部分。因爲@temp_target_list是每個線程,所以沒有協調。除非$num_of_targets_in_project被共享,並進行某種屏幕外協調,但沒有顯示。

基於文件的鎖定總是會成爲地獄的一小部分。線程有更好的協調機制。有一個更簡單的方法來做到這一點。

假設文件不是太大,請將每行讀入共享數組。然後讓每個線程從該數組中處理項目。該數組是共享的,因此每個元素都被刪除,數組將更新所有線程。喜歡的東西...

use strict; 
use warnings; 
use autodie; 

use threads; 
use threads::shared; 

my $Max_Threads = 5; 
my @Todo : shared; 

open my $fh, "<", $work_file; 
@Todo = <$fh>; 
close $fh; 

my @threads; 
for (1..$Max_Threads) { 
    push @threads, threads->new(\&compile_process); 
} 

$_->join for @threads; 

sub compile_process { 
    while(my $work = shift @Todo) { 
     ...do whatever with $work... 
    } 
} 

如果文件過大在內存中保存,可以使用Thread::Queue建設的工作項隊列,並動態地添加到它。

+0

謝謝!我會試試這個。 – user1625723