2013-03-25 6 views
6

मुझे डेल्फी में बहु थ्रेड के साथ समस्याएं आ रही हैं। मेरे पास नामों की एक सूची है (2.000 नामों के बारे में कुछ), और मुझे अपनी साइट में प्रत्येक नाम का कुछ डेटा प्राप्त करने की आवश्यकता है। धागा नियंत्रण को छोड़कर, मेरा सिस्टम पूरी तरह से काम करता है।मल्टी थ्रेड डेल्फी

मैं 10 धागे बनाना चाहता हूं, और, जब कुछ धागा समाप्त हो जाता है, तो सूची के अंत तक एक और बनाएं ...

var 
Form1: TForm; 
tCount: Integer; //threads count 

implementation 

type 
TCheck = class(TThread) 
public 
    constructor Create(Name: string); 
    destructor Destroy; Override; 
protected 
    procedure Execute; Override; 
end; 

MainT = class(TThread) 
protected 
    procedure Execute; Override; 
end; 

destructor TCheck.Destroy; 
begin 
Dec(tCount); 
end; 

procedure MainT.Execute; 
var 
i: Integer; 
Load: TStringList; 
begin 
Load:=TStringList.Create; 
Load.LoadFromFile('C:\mynames.txt'); 

for i:= 0 to Load.Count -1 do 
begin 

    if tCount = 10 then //if we have 10 threads running... 
    begin 
    repeat 
    Sleep(1); 
    until tCount < 10; 
    end; 

    TCheck.Create(Load.Strings[i]); 
    TCheck.Start; 
    Inc(tCount); 

end; 

end; // end of procedure 

ठीक है, मैं TCheck.Constructor डाल नहीं किया क्योंकि समस्या विधि मैं कैसे बनाया धागे की संख्या की जांच कर रहा हूँ है। मेरा मतलब है, मेरा सॉफ़्टवेयर बस बिना किसी त्रुटि संदेश के रोकता है, कभी-कभी 500 नामों की जांच करता है, कभी-कभी 150 नाम ...

खराब अंग्रेजी के लिए खेद है।

+0

क्या आप टीसीएचक सीटीआर पोस्ट कर सकते हैं? –

+5

इसके अलावा, यदि आप 10 धागे चाहते हैं, तो 10 धागे बनाएं और उन्हें अपने सभी कामों को क्यूइंग सामग्री से संसाधित करें। उन्हें लगातार बना/समाप्त/नष्ट न करें। टीकाउंट और माइक्रो-मैनेजिंग थ्रेड्स को भूल जाओ। –

+2

हाँ। आपको ऐसे निर्माता की आवश्यकता है जो थ्रेडसेफ कतार भरती है, और 10 उपभोक्ता इसे निकालें। –

उत्तर

3

यहाँ है जेनेरिक का उपयोग कर एक थ्रेडसेफ कतार समाधान।

परिभाषित करें कि कितने उपभोक्ता वें आपको लगता है कि कतार गहराई है, और धागे से DoSomeJob प्रक्रिया चलाएं।

एक सामान्य प्रक्रिया के रूप में एक स्ट्रिंग के साथ काम कर रहे अपने काम को परिभाषित करें (CaptureJob में)।

जब कतार खाली है, तो उपभोक्ता धागे नष्ट हो जाएंगे। DoSomeJob प्रक्रिया तब तक प्रतीक्षा करती है जब तक कि सभी नौकरियां तैयार न हों। आप इसे आसानी से एक सामान्य कार्यकर्ता पूल में बदल सकते हैं, धागे को फिर से नष्ट किए बिना पुन: उपयोग कर सकते हैं। नौकरी की वस्तुओं की सामान्य संरचना उन्हें विभिन्न प्रकार के कार्यों को संभालने के लिए उपयुक्त बनाती है।

नोट करें कि यह कतार XE2 और उसके बाद के संस्करण पर काम करती है। यदि आप पुराने डेल्फी संस्करण पर हैं, तो टिप्पणियों में सुझाए गए समान थ्रेडसेफ कतार की तलाश करें।

uses 
    Classes,SyncObjs,Generics.Collections; 

Type 
  TMyConsumerItem = class(TThread) 
  private 
    FQueue : TThreadedQueue<TProc>; 
    FSignal : TCountDownEvent; 
  protected 
    procedure Execute; override; 
  public 
    constructor Create(aQueue : TThreadedQueue<TProc>; aSignal : TCountdownEvent); 
  end; 

constructor TMyConsumerItem.Create(aQueue: TThreadedQueue<TProc>); 
begin 
    Inherited Create(false); 
    Self.FreeOnTerminate := true; 
    FQueue := aQueue; 
    FSignal := aSignal; 
end; 

procedure TMyConsumerItem.Execute; 
var 
    aProc : TProc; 
begin 
    try 
    repeat 
     FQueue.PopItem(aProc); 
     if not Assigned(aProc) then 
     break; // Drop this thread 
     aProc(); 
    until Terminated; 
    finally 
    FSignal.Signal; 
    end; 
end; 

procedure DoSomeJob(myListItems : TStringList); 
const 
    cThreadCount = 10; 
    cMyQueueDepth = 100; 
var 
    i : Integer; 
    aQueue : TThreadedQueue<TProc>; 
    aCounter : TCountDownEvent; 
    function CaptureJob(const aString : string) : TProc; 
    begin 
    Result := 
     procedure 
     begin 
     // Do some job with aString 
     end; 
    end; 
begin 
    aQueue := TThreadedQueue<TProc>.Create(cMyQueueDepth); 
    aCounter := TCountDownEvent.Create(cThreadCount); 
    try 
    for i := 1 to cThreadCount do 
     TMyConsumerItem.Create(aQueue,aCounter); 
    for i := 0 to myListItems.Count-1 do begin 
     aQueue.PushItem(CaptureJob(myListItems[i])); 
    end; 
    finally 
    for i := 1 to cThreadCount do 
     aQueue.PushItem(nil); 
    aCounter.WaitFor; // Wait for threads to finish 
    aCounter.Free; 
    aQueue.Free; 
    end; 
end; 

नायब: केन बताता है कि क्यों अपने प्रारंभ और धागे की शुरुआत गलत हैं। यह प्रस्ताव अधिक सामान्य तरीके से इस प्रकार की समस्याओं को संभालने के लिए एक बेहतर संरचना दिखाता है।

+0

यह स्पष्ट नहीं करता है कि प्रश्न का कोड कैसे काम नहीं करता है। डेल्फी के किस संस्करण का उपयोग किया जा रहा है, इसके मूल प्रश्न में कोई संकेत नहीं है, इसलिए यह स्पष्ट नहीं है कि जेनेरिक एक विकल्प है। (उपरोक्त मेरे उत्तर के अंतिम दो पैराग्राफ देखें।) :-) (डाउनवॉटिंग नहीं - बस एक टिप्पणी छोड़ना।) –

+1

@ केन व्हाइट, क्षमा करें, यह उत्तर सिर्फ यह दिखाने के लिए था कि इस समस्या को बेहतर संरचना के साथ कैसे हल किया जा सकता है। पोस्टर कोड में त्रुटि को स्पॉट करने के लिए आपको सभी क्रेडिट। –

1

आप एक चर TCheck.Create के रिटर्न मान धारण करने के लिए यह घोषित नहीं करते, तो आप TCheck.Start उपयोग नहीं कर सकते (वहाँ TCheck का कोई उदाहरण आप Start विधि का उपयोग करने के लिए उपयोग कर सकते है)। ताकि आप इसे उपयोग करने के लिए की जरूरत नहीं है,

Check := TCheck.Create(Load[i]); { See note below } 
Check.Start; 
Inc(tCount); 

नोटTStringList की सामान्य प्रॉपर्टी Strings है:

उचित तरीके से एक var Check: TCheck;MainT.Execute अंदर घोषित करने के लिए, और फिर मान दिया स्टोर होगा । जैसा कि मैंने ऊपर दिया है, आप सीधे Strings तक पहुंच सकते हैं। अगले दो पंक्तियों बिल्कुल वही बात कर रहे हैं (लेकिन स्पष्ट रूप से एक टाइप करने का छोटा और आसान है):

Load.Strings[i]; 
Load[i]; 

आप TCheck के लिए एक संदर्भ रखने के लिए नहीं करना चाहते हैं, बस एक with ब्लॉक होने के लिए अपना कोड बदलें (begin..end सहित, और ब्लॉक में कोई अन्य कोड युक्त (इस है एक ही रास्ता मैंने कभी उपयोग करने की अनुशंसा एक with):

with TCheck.Create(Load[i]) do 
begin 
    Start; 
    Inc(tCount); 
end; 

इसके साथ ही कहा जा रहा है, वहाँ काफी बेहतर तरीकों से आप यह कर सकते हैं कर रहे हैं सभी प्रकार के वें बनाने/नष्ट करने के बजाय पढ़ता है। जैसा कि अन्य ने कहा है, आपके पास 10 धागे की सूची हो सकती है और उनके लिए काम कतार हो सकती है, ताकि प्रत्येक Load से किसी आइटम को संसाधित कर सके और फिर पूरा होने पर प्रक्रिया करने के लिए एक और आइटम प्राप्त करने के लिए वापस आएं, और सूची पूर्ण होने तक दोहराएं। यह कहना मुश्किल है कि आप यह कैसे करेंगे, क्योंकि यह आपके डेल्फी संस्करण पर निर्भर करेगा। (पुस्तकालय उपलब्ध हैं जो OMNIThreadLibrary जैसे आपके लिए अधिकांश काम करेंगे, लेकिन यह डेल्फी के कुछ पुराने संस्करणों के लिए उपलब्ध नहीं है। डेल्फी के हाल के संस्करण भी TQueue और TObjectQueue और कुछ अन्य प्रकार और कार्यक्षमता का समर्थन करते हैं जो बहुत उपयोगी हो सकते हैं।

(आप कैसे धागे की एक सीमित संख्या के साथ एक कतार में यह करने के लिए के बारे में एक अलग प्रश्न है, तो है कि एक नया सवाल, कुछ नहीं तो आप इस एक में जोड़ने के लिए होना चाहिए।)

संबंधित मुद्दे