2009-07-17 16 views
9

मैं एक दूरस्थ शेयर (एक विंडोज सर्वर पर) में एक फ़ाइल के अस्तित्व का परीक्षण कर रहा हूँ। परीक्षण के लिए उपयोग किया जाने वाला अंतर्निहित फ़ंक्शन WinAPI का GetFileAttributes है, और क्या होता है कि यह कार्य विभिन्न परिस्थितियों में अनजान समय (दर्जनों सेकंड) ले सकता है, जैसे लक्ष्य सर्वर ऑफलाइन होने पर, अधिकार या DNS समस्याएं होती हैं, इत्यादिGetFileAttributes में नेटवर्क स्टालों से कैसे बचें?

हालांकि, मेरे विशेष मामले में, यह हमेशा एक लैन पहुंच है, इसलिए यदि फ़ाइल को 1 सेकंड से भी कम समय में एक्सेस नहीं किया जा सकता है, तो यह आमतौर पर दर्जनों सेकंड प्रतीक्षा करके पहुंच योग्य नहीं होगा ..

क्या GetFileAttributes के लिए कोई विकल्प है जो स्टॉल नहीं करेगा? (इसे एक थ्रेड में कॉल करने और थ्रेड के बाद थ्रेड को मारने के अलावा, जो कि अपने स्वयं के मुद्दों का बैग लाता है)

+0

नहीं कर सकते अतुल्यकालिक मॉडल को छोड़कर किसी भी बात के बारे में सोच। –

+0

अन्य परिस्थितियों में, मैंने साझा फ़ाइलों की सेवा के लिए न्यूनतम-वेब सर्वर को तैनात करके इस समस्या को हल किया है, क्योंकि एक HTTP अनुरोध आसानी से रद्द/समय-समय पर रद्द किया जा सकता है। लेकिन इस मामले में, यह विभिन्न कारणों (तैनाती सिरदर्द, सुरक्षा मुद्दों इत्यादि) के लिए कोई समाधान नहीं है। –

उत्तर

6

समस्या वास्तव में GetFileAttributes नहीं है। यह आमतौर पर अंतर्निहित फ़ाइल सिस्टम ड्राइवर को केवल एक कॉल का उपयोग करता है। यह है कि आईओ जो रोक रहा है।

फिर भी, समाधान शायद आसान है। एक सेकंड के बाद CancelSynchronousIo() पर कॉल करें (यह स्पष्ट रूप से दूसरे थ्रेड की आवश्यकता है क्योंकि आपका पहला GetFileAttributes के अंदर फंस गया है)।

+0

ध्यान दें कि रद्द करें सिंक्रोनसआईओ विंडोज एक्सपी में उपलब्ध नहीं है। –

+0

@MSalters: GetFileAttributes विधि का उपयोग करते समय मुझे पहुंच प्राप्त हो रही है (5) त्रुटि। मेरे पास कम हार्डवेयर कॉन्फ़िगरेशन वाला विंडो 2003 सर्वर है। मैंने अन्य सिस्टम पर अनुमति अक्षम के साथ एक ही कॉल की कोशिश की जो पूरी तरह से काम करता था। आईओ कारण धीमा कर सकते हैं "पहुंच अस्वीकार कर दिया गया है" त्रुटि। –

+0

@RahulKP: काफी संभावना नहीं है। – MSalters

4

प्रतिनिधियों के बारे में एक अच्छी बात यह है कि आप हमेशा BeginInvoke और EndInvoke कर सकते हैं। बस सुनिश्चित करें कि बुलाया गया तरीका अपवाद नहीं फेंकता है क्योंकि [मुझे विश्वास है] यह एक क्रैश (अनचाहे अपवाद) का कारण बन जाएगा।

AttributeType attributes = default(AttributeType); 

Action<string> helper = 
    (path) => 
    { 
     try 
     { 
      // GetFileAttributes 
      attributes = result; 
     } 
     catch 
     { 
     } 
    }; 
IAsyncResult asyncResult = helper.BeginInvoke(); 
// whatever 
helper.EndInvoke(); 
// at this point, the attributes local variable has a valid value. 
+1

तो मूल रूप से, किसी थ्रेड में एपीआई कॉल को लपेटने के बाहर कोई उम्मीद नहीं है? मैं धागे के बाहर एक समाधान की उम्मीद कर रहा था, क्योंकि एक समय पर धागे को मारना "साफ" नहीं है (अनुभव से, बुरी चीजें हो सकती हैं), और स्थगित धागे को अनदेखा कर सकता है संभावित रूप से पूरे स्टॉल किए गए धागे का कारण बन सकता है ... –

+0

क्षमा करें, ऐसा लगता है कि मैंने गलती से माना कि आप .NET में काम कर रहे थे (इससे पहले उनमें से कुछ का जवाब दिया)। यदि एपीआई में एसिंक्रोनस और/या टाइमआउट संस्करण उपलब्ध नहीं है, तो थ्रेडिंग समाधान एकमात्र विश्वसनीय समाधान हो सकता है। –

0

मुझे लगता है कि काम करने के लिए थ्रेड-पूल थ्रेड का उपयोग करना आपका सबसे अच्छा समाधान है।

  • अपने धागा समारोह पूरा करता है जब, धागा स्वचालित रूप से वापस लौट एक फ़ाइल
  • GetFileAttributes पूरा होने से रन
  • अपने फ़ॉर्म पर वापस पोस्ट परिणाम जाने की विशेषताओं क्वेरी करने के लिए काम की एक इकाई आवंटित पूल में (इसे मारने की कोई ज़रूरत नहीं है)

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

TGetFileAttributesData = class(TObject) 
public 
    Filename: string; 
    WndParent: HWND; 
    Attributes: DWORD; 
    constructor Create(Filename: string; WndParent: HWND); 
end; 
:

RunInThreadPoolThread(
     GetFileAttributesThreadMethod, 
     TGetFileAttributesData.Create('D:\temp\foo.xml', Self.Handle), 
     WT_EXECUTEDEFAULT); 

आप धागा डेटा जानकारी धारण करने के लिए वस्तु बनाने:

तो फिर आप अपने काम सहायक विधि है कि QueueUserWorkItem का उपयोग कर एक धागा पूल धागे पर एक वस्तु की विधि प्रक्रिया चलाता है

procedure TForm1.GetFileAttributesThreadMethod(Data: Pointer); 
var 
    fi: TGetFileAttributesData; 
begin 
    fi := TObject(Data) as TGetFileAttributesData; 
    if fi = nil then 
     Exit; 

    fi.attributes := GetFileAttributes(PWideChar(fi.Filename)); 

    PostMessage(fi.WndParent, WM_GetFileAttributesComplete, NativeUInt(Data), 0); 
end; 

टी:

और आप अपने धागा कॉलबैक विधि बनाने मुर्गी तुम सिर्फ संदेश संभाल:

procedure WMGetFileAttributesComplete(var Msg: TMessage); message WM_GetFileAttributesComplete; 

procedure TfrmMain.WMGetFileAttributesComplete(var Msg: TMessage); 
var 
    fi: TGetFileAttributesData; 
begin 
    fi := TObject(Pointer(Msg.WParam)) as TGetFileAttributesData; 
    try 
     ShowMessage(Format('Attributes of "%s": %.8x', [fi.Filename, fi.attributes])); 
    finally 
     fi.Free; 
    end; 
end; 

जादुई RunInThreadPoolThread आप एक सूत्र में एक उदाहरण विधि पर अमल देता है कि फुलाना की सिर्फ एक सा है:

सिर्फ एक आवरण आप एक पर विधि कॉल करने देता है कौन सा उदाहरण चर:

TThreadMethod = procedure (Data: Pointer) of object; 

TThreadPoolCallbackContext = class(TObject) 
public 
    ThreadMethod: TThreadMethod; 
    Context: Pointer; 
end; 

function ThreadPoolCallbackFunction(Parameter: Pointer): Integer; stdcall; 
var 
    tpContext: TThreadPoolCallbackContext; 
begin 
    try 
     tpContext := TObject(Parameter) as TThreadPoolCallbackContext; 
    except 
     Result := -1; 
     Exit; 
    end; 
    try 
     tpContext.ThreadMethod(tpContext.Context); 
    finally 
     try 
      tpContext.Free; 
     except 
     end; 
    end; 
    Result := 0; 
end; 

function RunInThreadPoolThread(const ThreadMethod: TThreadMethod; const Data: Pointer; Flags: ULONG): BOOL; 
var 
    tpContext: TThreadPoolCallbackContext; 
begin 
    { 
     Unless you know differently, the flag you want to use is 0 (WT_EXECUTEDEFAULT). 

     If your callback might run for a while you can pass the WT_ExecuteLongFunction flag. 
       Sure, I'm supposed to pass WT_EXECUTELONGFUNCTION if my function takes a long time, but how long is long? 
       http://blogs.msdn.com/b/oldnewthing/archive/2011/12/09/10245808.aspx 

     WT_EXECUTEDEFAULT (0): 
       By default, the callback function is queued to a non-I/O worker thread. 
       The callback function is queued to a thread that uses I/O completion ports, which means they cannot perform 
       an alertable wait. Therefore, if I/O completes and generates an APC, the APC might wait indefinitely because 
       there is no guarantee that the thread will enter an alertable wait state after the callback completes. 
     WT_EXECUTELONGFUNCTION (0x00000010): 
       The callback function can perform a long wait. This flag helps the system to decide if it should create a new thread. 
     WT_EXECUTEINPERSISTENTTHREAD (0x00000080) 
       The callback function is queued to a thread that never terminates. 
       It does not guarantee that the same thread is used each time. This flag should be used only for short tasks 
       or it could affect other timer operations. 
       This flag must be set if the thread calls functions that use APCs. 
       For more information, see Asynchronous Procedure Calls. 
       Note that currently no worker thread is truly persistent, although worker threads do not terminate if there 
       are any pending I/O requests. 
    } 

    tpContext := TThreadPoolCallbackContext.Create; 
    tpContext.ThreadMethod := ThreadMethod; 
    tpContext.Context := Data; 

    Result := QueueUserWorkItem(ThreadPoolCallbackFunction, tpContext, Flags); 
end; 

पाठक के लिए व्यायाम: GetFileAttributesData उद्देश्य यह है कि वें बताता अंदर एक रद्द झंडा बनाएं ई धागा कि यह को डेटा ऑब्जेक्ट को मुक्त करना होगा और अभिभावक को संदेश पोस्ट करना होगा।


यह सब कह रही है कि आप बना रहे हैं की एक लंबा रास्ता है:

DWORD WINAPI GetFileAttributes(
    _In_  LPCTSTR       lpFileName, 
    _Inout_ LPOVERLAPPED     lpOverlapped, 
    _In_  LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine 
); 
+0

पूल किए गए धागे का उपयोग करने से समस्या हल नहीं होती है कि थ्रेड को बहुत लंबे समय तक रोक दिया जा सकता है क्योंकि GetFileAttributes कुछ नेटवर्किंग टाइमआउट के लिए प्रतीक्षा कर रहा है। इसके अलावा किसी को अप्रासंगिक धागे को अनदेखा करने की आवश्यकता है। उदाहरण के लिए यदि आप 10 सेकंड के साथ दो बार एक ही फाइल से पूछते हैं, तो पहला कॉल 30 सेकंड के लिए फंस सकता है, जबकि दूसरा तुरंत सफल हो सकता है (और आपको पहले कॉल के परिणामों को अनदेखा करने की आवश्यकता है)। इसके अलावा यदि आप कुछ सेकंड की आवृत्ति के साथ कई फाइलों की निगरानी करते हैं, तो यह दर्जनों या यहां तक ​​कि सैकड़ों स्टॉल किए गए धागे के साथ "आसान" है ...बिल्कुल व्यावहारिक नहीं:/ –

+0

अप्रासंगिक धागे को अनदेखा करना उसी तरह हल किया गया है जैसे कि विंडोज ने पहले से ही एक ओवरलैप्ड प्रदान किया है (यानी एसिंक्रोनस) 'GetFileAttributesEx' संस्करण - आपको मौजूदा कॉल को रद्द करना होगा। यह अभ्यास द्वारा हल किया जाता है। आपकी चिंता यह है कि जब आपके पास दर्जन या सैकड़ों स्टैल्ड थ्रेड होते हैं तो क्या करना है। मैं प्रस्तुत करता हूं कि यह कोई चिंता नहीं है, क्योंकि उपयोगकर्ता कार्य आइटम कतार आइटम को कतार में रखेगी जब तक कि पुरानी वस्तुओं को कतार से फ़्लश नहीं किया जाता है। हालांकि, [आप इसे मदद करने के लिए कुछ भी कर सकते हैं] (http://msdn.microsoft.com/en-us/library/windows/desktop/aa363794.aspx) धागे को पूल में तेज़ी से वापस कर देगा। –

+0

यह भी उपयोगी नहीं है कि 'QueueUserWorkItem' * आपके आइटम * कतार * होगा; और सैकड़ों धागे नहीं बनाते हैं। 'QueueUserWorkItem' के प्रयोजनों में से एक आपको * कतार * कार्य आइटमों को बताने के लिए है - थ्रेड पूल निर्णय लेता है जब वे निष्पादित करेंगे। –

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