2012-03-19 20 views
5

मैं बहु-थ्रेडेड ऐप प्रोग्रामिंग कर रहा हूं। मेरे पास दो धागे हैं डिवाइस से कुछ डेटा को वैश्विक डेटा बफर में स्थानांतरित करने के लिए है और दूसरा डेटा को फ़ाइल में लिखने के लिए है।धागे के भीतर डेटा के लिए प्रतीक्षा करने और फ़ाइल में लिखने के तरीके पर सबसे अच्छा अभ्यास?

डिवाइस से बफर तक डेटा अतुल्यकालिक रूप से स्थानांतरित हो रहा है। दूसरे धागे का उद्देश्य मुख्य डेटा बफर में निर्दिष्ट मात्रा में डेटा को लिखने के लिए और आखिर में फ़ाइल में लिखने के लिए प्रतीक्षा करना चाहिए।

वैसे पहला धागा डीएलएल में है और दूसरा मुख्य ऐप में है। अस्थायी रूप से मैं इसे घटनाओं के साथ हल करता हूं। पहला धागा डिवाइस से डेटा को मुख्य डेटा बफर में स्थानांतरित करता है और डेटा की गणना करता है और जब निर्दिष्ट मात्रा में डेटा स्थानांतरित किया जाता है तो यह एक ईवेंट सेट करता है। दूसरा व्यक्ति घटना के संकेत के लिए इंतजार कर रहा है और जब यह डेटा स्टोर के लिए कुछ कोड चलाता है। सरल है कि यह काम कर रहा है।

Thread1.Execute: 

    var DataCount, TransferedData: Integer; 

    DataCounter := 0; 
    while not Terminted do 
    begin 
    TransferData(@pData, TransferedData); 
    Inc(DataCounter, TransferedData) 
    if DataCounter >= DataCountToNotify then SetEvent(hDataCount); 
    end; 



    Thread2.Execute: 

    hndlArr[0] := hDataCount; 
    hndlArr[1] := hTerminateEvent; 

    while (not Terminated) do 
    begin 
    wRes := WaitForMultipleObjects(HandlesCount, Addr(hndlArr), false, 60000); 
    case wRes of 
     WAIT_OBJECT_0: 
     begin 
      Synchronize(WriteBuffer);     // call it from main thread 
      ResetEvent(hndlArr[0]); 
     end; 
     WAIT_OBJECT_0 + 1: 
     begin 
      ResetEvent(hTerminateEvent); 
      break; 
     end; 
     WAIT_TIMEOUT: Break; 
    end; 
    end; 

अब मैं दूसरे धागे अधिक स्वतंत्र बनाने के लिए चाहते हैं ... इसलिए मैं दूसरे धागे के कई उदाहरण बना सकते हैं और मैं पहली बार धागा के लिए प्रतीक्षा करने की जरूरत नहीं है। मैं कोड के डेटा गिनती हिस्से को पहले धागे से दूसरे में स्थानांतरित करना चाहता हूं, इसलिए मुझे पहले धागे में डेटा गिनती की आवश्यकता नहीं होगी। पहला डेटा हस्तांतरण उद्देश्य के लिए होगा।

मैं डेटा काउंटर के रूप में दूसरा डेटा उपयोग करने और डेटा स्टोर करने के लिए उपयोग करना चाहता हूं। लेकिन अब मुझे लूप करना होगा और निर्दिष्ट डेटा राशि के लिए मैन्युअल रूप से जांचना होगा। अगर मेरे पास लूप था तो मुझे कुछ नींद जोड़नी पड़ेगी, इसलिए दूसरा थ्रेड कंप्यूटर प्रदर्शन को कम नहीं करेगा, लेकिन मुझे नहीं पता कि कितनी देर तक सोना चाहिए जबकि फ़र्ट्स थ्रेड में डेटा ट्रांसफर की गति स्थिर नहीं है और इस प्रकार दूसरे थ्रेड में गिनती की गति अंतर होगा।

मेरा अनुमान है कि इस कोड नमूना अच्छा नहीं है:

Thread2.Execute: 
    var DataCount: Integer; 
    DataIdx1 := GetCurrentDataIdx; 
    while (not Terminated) do 
    begin  
    if (GetCurrentDataIdx - DataIdx1) >= DataCountToNotify then 
    begin 
     Synchronize(WriteBuffer); 
     DataIdx1 := GetCurrentIdx; 
    end; 
    sleep(???); 
    end; 

तो मेरे सवाल का क्या डेटा गिनती के साथ कि इस मुद्दे को और दूसरा धागा भीतर भंडारण हल करने के लिए सबसे अच्छा तरीका क्या है? आपके अनुभव और सुझाव क्या हैं?

+3

आप फाइल के लेखन को मुख्य धागे पर क्यों मजबूर करते हैं, 'सिंक्रनाइज़ (लिखेंबफर)'? मुझे समझ में नहीं आता कि आप दूसरे थ्रेड को गुणा करने के लिए कैसे प्रबंधित करेंगे और अभी भी एक फ़ाइल में लिखने के क्रम को बनाए रखें। –

+0

थ्रेड गुणा किया जाएगा लेकिन डेटा विभिन्न फ़ाइलों में संग्रहीत किया जाएगा। मैंने कहीं भी लिखा नहीं है कि मैं इसे एक ही फाइल में लिखने जा रहा हूं। मेरा लक्ष्य एकाधिक नियंत्रण रखना है जो एक ही स्रोत से डेटा को विभिन्न फ़ाइलों में स्टोर करने में सक्षम हैं। – Nix

+0

यह जानना अच्छा है, क्योंकि उत्तर इस जानकारी पर निर्भर करेगा। फिर भी मुझे आश्चर्य है कि फ़ाइल लेखन मुख्य धागे को क्यों लागू किया जाना चाहिए। –

उत्तर

5

आपके पास कुछ समस्याएं हैं। @ एलयू आरडी ने पहले से ही एक को इंगित किया है - उन चीजों को सिंक्रनाइज़ न करें जिन्हें सिंक्रनाइज़ करने की आवश्यकता नहीं है। यह स्पष्ट नहीं है कि 'WriteBuffer' क्या करता है, लेकिन फ़ाइल सिस्टम और मेरे द्वारा उपयोग किए जाने वाले सभी डेटाबेस ठीक हैं, एक थ्रेड एक फ़ाइल/टेबल खोलने और उन्हें लिखने के लिए ठीक है।

आपकी बफर प्रणाली शायद कुछ ध्यान से कर सकती है। क्या कुछ 'निर्दिष्ट डेटा राशि' है या क्या यह कुछ वास्तविक आंकड़ा है जो आलसी लेखन की अनुमति देता है?

आमतौर पर, निर्माता और उपभोक्ता धागे कतारों पर एकाधिक बफर पॉइंटर्स का आदान-प्रदान करते हैं और इसलिए किसी भी एकल बफर को साझा करने से बचें। यह देखते हुए कि यह एक डीएलएल है और इसलिए मेमोरी-प्रबंधन कॉल समस्याग्रस्त हो सकते हैं, मैं शायद सिस्टम के चारों ओर डेटा स्थानांतरित करने के लिए स्टार्टअप पर बफर का पूल बनाकर भी उनसे बचूंगा। मैं सिर्फ पॉइंटर्स को स्मृति के बजाय बफर क्लास का उपयोग करता हूं, लेकिन यह बिल्कुल जरूरी नहीं है, (बस इतना आसान/लचीला/सुरक्षित)।

नींद() लूप थ्रेड के बीच संचार करने का एक शानदार तरीका है। नींद() इसका उपयोग करता है, लेकिन यह उनमें से एक नहीं है। डेल्फी/विंडोज में सिंक्रनाइज़ेशन तंत्र के बहुत सारे हैं - घटनाएं, सेमफोर, म्यूटेक्स इत्यादि - इस तरह के मतदान अनावश्यक बनाते हैं।

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

+0

ऊपरी कोड सिर्फ डेमो उद्देश्य के लिए है। सिंक्रनाइज़ करने के साथ परेशान मत करो। मेरे पास पहले से ही निश्चित चीजें हैं और मैं थ्रेड इत्यादि को सिंक्रनाइज़ करने के लिए उचित तंत्र का उपयोग करता हूं। जैसा कि मैंने उल्लेख किया है कि मैं डेटा गिनना चाहता हूं और फिर जब स्थिति पर लागू होता है। DataCountToNotify = 8192 मैं डेटा स्टोर करना चाहता हूं। लेकिन मैं नींद से बचना चाहूंगा। क्या ऐसा कोई अन्य विकल्प है कि ऐसा कैसे करें? – Nix

+0

@Nix अगर मुझे गलत नहीं लगता है, तब तक जब आपका धागा थोड़ी देर में "कुछ" करता है, तो आप "नींद" छोड़ सकते हैं, लेकिन आप नींद (1) का उपयोग कर सकते हैं जो कि 1 और 55 एमएस (जीत xp में कोई समस्या है, भविष्य के संस्करणों के बारे में निश्चित नहीं है) – ComputerSaysNo

+1

@DorinDuminica, [थ्रेड-नींद-एक-साइन-ऑफ-ए-ग़रीब-डिज़ाइन-प्रोग्राम] देखें (https://msmvps.com/ थ्रेड में 'स्लीप' का उपयोग करने के खिलाफ तर्कों के लिए ब्लॉग/पेटीरिची/संग्रह/2007/04/26/थ्रेड-नींद-एक-एक-खराब-डिज़ाइन-प्रोग्राम.एएसपीएक्स)। –

2

यदि आप Sleep() से अपने दूसरे थ्रेड में कॉल करना चाहते हैं, तो TSimpleEvent जैसे प्रतीक्षा करने योग्य टाइमर का उपयोग करें।

अपनी सभी समय की स्थिति को संभालने के लिए नींद का समय निर्धारित करें। सामान्य Sleep() की बजाय इस योजना का उपयोग करने का एक फायदा है, क्योंकि एक प्रतीक्षा करने योग्य टाइमर धागे को गहरी नींद में नहीं डाल देगा।

धागे का निपटान करने के लिए, कोड में टिप्पणियां देखें।

var 
    FEvent: TSimpleEvent; 
    FSleepTime: Integer = 100; // Short enough to handle all cases 

Constructor TThread2.Create; 
begin 
    Inherited Create(False); 
    FEvent := TSimpleEvent.Create; 
    Self.FreeOnTerminate := True; 
end; 

procedure TThread2.Execute; 
var 
    DataCount: Integer; 
begin 
    DataIdx1 := GetCurrentDataIdx; 
    while (fEvent.WaitFor(FSleepTime) = wrTimeout) do 
    begin 
    if Terminated then 
     break; 
    // Do your work 
    if (GetCurrentDataIdx - DataIdx1) >= DataCountToNotify then 
    begin 
     // Write data to buffer 
     DataIdx1 := GetCurrentIdx; 
    end; 
    end; 
end; 

// To stop the thread gracefully, call this instead of Terminate or override the DoTerminate 
procedure TThread2.SetTerminateFlag; 
begin 
    FEvent.SetEvent; 
end; 
+0

LU RD धन्यवाद यह बहुत ही आशाजनक दिखता है। पहले थ्रेड में डेटा ट्रांसफर की गति के आधार पर मुझे एफएसपीई समय बदलना होगा। मैं उस समय की गणना कर सकता हूं। जैसे मैंने कहा कि मैं सोने में सोने से बचने की कोशिश करता हूं इसलिए मैं सोने के लिए बेहतर विकल्प ढूंढ रहा था। मैंने कभी भी प्रोग्राम किए गए किसी भी थ्रेड में नींद का उपयोग नहीं किया है। मुझे यह बहुत सुरक्षित नहीं मिला। मुझे सिस्टम को और अधिक दृढ़ संकल्प करना पसंद है। बहुत बहुत धन्यवाद। मैं आपको सुझाए गए तरीके से इसका एहसास करने की कोशिश करूंगा। – Nix

+0

यह पहली बार देखने पर उचित है, लेकिन ऐसा नहीं है। क्या आपको 'wrTimeout' के बजाय 'wrSignaled' का मतलब था? इसके अलावा, यहां अभी भी सिक्रोनोनाइज़ कॉल है जो थ्रेड को अप्रभावी से भी बदतर बनाता है - यह वास्तव में अधिक देरी पेश करेगा। –

+0

@ मार्टिनजेम्स, सिंक्रनाइज़ेशन स्पष्ट रूप से गलत है, लेकिन ओपी ने कहा कि यह अब कोई समस्या नहीं थी। लूप जारी रहेगा जबकि संकेत नहीं दिया जाएगा (हर FSleepTime मिलीसेकंद)। यह मेरे दिमाग में ठीक दिखता है। –