2015-10-22 56 views
4

我在多線程環境中使用MQSeries Perl模塊時出現問題。在這裏我曾嘗試過:多線程與MQ

  • 在不同的線程中創建兩個句柄與$mqMgr = MQSeries::QueueManager->new()。我認爲這會給我兩種不同的MQ連接,但是在第二次調用MQOPEN()時,我得到了返回碼2219,這可能意味着我通過兩次單獨調用new()方法獲得了與mq相同的下層連接。
  • 聲明只有一個$ mqMgr全球共享變量。但是我不能將對MQSeries :: QueueManager對象的引用分配給$mqMgr。原因是「參數:: shared :: shared的arg 1的類型必須是[$ @%]之一(不是子例程條目)」
  • 只聲明一個$mqMgr作爲全局變量。得到相同的2219代碼。
  • 試圖將MQCNO_HANDLE_SHARE_NO_BLOCK轉換爲MQSeries::QueueManager->new(),以便跨線程共享單個連接。但我不能找到一種方法,通過它英寸

我的問題是,用Perl模塊的MQSeries

  • 我如何/可以從不同的線程來MQ隊列管理單獨的連接?
  • 如何在不同的線程上共享MQ隊列管理器的連接?

我環顧四周,但有一點運氣,任何信息,將不勝感激。

相關的問題:


更新1:添加例如兩個地方的MQSeries ::兩個線程事業MQ錯誤代碼的QueueManager對象2219

use threads; 
use Thread::Queue; 
use MQSeries; 
use MQSeries::QueueManager; 
use MQSeries::Queue; 

# globals 
our $jobQ = Thread::Queue->new(); 
our $resultQ = Thread::Queue->new(); 

# ---------------------------------------------------------------------------- 
# sub routines 
# ---------------------------------------------------------------------------- 

sub worker { 
    # fetch work from $jobQ and put result to $resultQ 
    # ... 
} 

sub monitor { 
    # fetch result from $resultQ and put it onto another MQ queue 
    my $mqQMgr = MQSeries::QueueManager->new(...); 

    # different queue from the one in main 
    # this would cause error with MQ code 2219 
    my $mqQ = MQSeries::Queue->new(...); 

    while (defined(my $result = $resultQ->dequeue())) { 
     # create an mq message and put it into $mqQ 
     my $mqMsg = MQSeries::Message->new(); 
     $mqQ->put($mqMsg); 
    } 
} 

# main 
unless (caller()) { 
    # create connection to MQ 
    my $mqQMgr = MQSeries::QueueManager->new(...); 
    my $mqQ = MQSeries::Queue->new(...); 

    # create worker and monitor thread 
    my @workers; 
    for (1 .. $nThreads) { 
     push(@workers, threads->create('worker')); 
    } 
    my $monitor = threads->create('monitor'); 

    while (True) { 
     my $mqMsg = MQSeries::Message->new(); 

     my $retCode = $mqQ->get(
      Message => $mqMsg, 
      GetMsgOptions => $someOption, 
      Wait => $sometime 
     ); 

     die("error") if ($retCode == 0); 
     next if ($retCode == -1); # no message 

     # not we have some job to do 
     $jobQ->enqueue($mqMsg->Data); 
    } 
} 
+0

包含一些示例代碼可能很有用 - 例如[MVCE](http://stackoverflow.com/help/mcve)。 – Sobrique

+0

@Sobrique感謝您的建議,添加了示例。 – Sky

+0

你在Win32上嗎? – Sobrique

回答

2

嘗試使用多線程時存在非常實際的危險使用模塊不是線程安全的模塊。有一堆東西,可以剛剛突破,因爲這樣穿的亂七八糟的作品 - 你克隆當前的進程狀態,這包括像文件句柄,插座等

但是,如果你嘗試使用他們以異步/線程的方式,他們會動作真的奇怪,因爲操作不(必然)原子。

因此,雖然我不能直接回答你的問題,因爲我沒有特定的模塊的經驗:

除非你知道,否則,假設你可以在線程之間沒有份額。它可能是線程安全的,它可能不是。如果不是,它仍然可能看起來沒問題,直到有一天,由於併發條件下的競爭條件,你會很難發現錯誤。

threads::shared中明確描述了共享標量/列表,因爲它基本上是安全的(即使如此,如果沒有鎖定,仍然可能存在非原子性問題)。

因此,我要建議你需要做的是兩種:

  • 有一個「通訊科」線程,但這所有相關模塊的工作,並使其他線程使用IPC與之交談。 Thread::Queue可以很好地爲此工作。

  • 將每個線程視爲完全獨立於模塊的目的。這包括加載它(使用requireimport - 不是use,因爲它更早),並實例化。 (您可能擺脫「加載」模塊線程開始之前,但實例化確實像創建描述符,插座等的事情)

  • 鎖的東西時,有一個原子操作中斷的危險。

大部分上面的也適用於fork並行 - 但是不是完全一樣的方式,爲fork使「共享」的東西相當困難,所以你不太可能在它絆倒。

編輯:

看着你已經發布的代碼,並crossreferencing對MQSeries來源:

  • 有一個BEGIN塊,設置了一些東西,以與MQSeries在該點你use吧。

雖然我不能肯定地說這是你的問題,但它使我非常謹慎 - 因爲記住當它這樣做時,它會設置一些東西 - 然後當你的線程開始時,它們在「BEGIN」塊中繼承「不管它」的非共享副本。

所以在我前面上建議輕 - 我建議你嘗試(因爲我不能肯定地說,因爲我沒有一個參考實現):

require MQSeries; 
MQSeries->import; 

認沽這在你的代碼中 - 代替use - 線程啓動。例如。在你執行了creates之後的之後的線程子例程。