2008-11-05 12 views
111

मुझे अभी एहसास हुआ कि मेरे कोड में किसी स्थान पर मेरे पास लॉक के अंदर रिटर्न स्टेटमेंट है और कभी-कभी बाहर है। कौन सा सबसे अच्छा है?क्या रिटर्न स्टेटमेंट लॉक के अंदर या बाहर होना चाहिए?

1)

void example() 
{ 
    lock (mutex) 
    { 
    //... 
    } 
    return myData; 
} 

2)

void example() 
{ 
    lock (mutex) 
    { 
    //... 
    return myData; 
    } 

} 

एक कौन सा उपयोग करना चाहिए?

+0

परावर्तक फायरिंग और कुछ आईएल तुलना ;-) कर के बारे में कैसे। –

+6

@ पॉप: किया गया - आईएल शर्तों में न तो बेहतर है - केवल सी # शैली लागू होती है –

+1

बहुत रोचक, वाह आज मैं कुछ सीखता हूं! – Pokus

उत्तर

155

अनिवार्य रूप से, जो कोड को सरल बनाता है। बाहर निकलने का एकल बिंदु एक अच्छा आदर्श है, लेकिन मैं इसे प्राप्त करने के लिए कोड को आकार से बाहर नहीं करूँगा ... और यदि विकल्प स्थानीय चर (लॉक के बाहर) घोषित कर रहा है, इसे प्रारंभ करना (लॉक के अंदर) और फिर इसे वापस (लॉक के बाहर), फिर मैं कहूंगा कि लॉक के अंदर एक साधारण "रिटर्न फू" बहुत आसान है।

आईएल में अंतर दिखाने के लिए, की सुविधा देता है कोड:

static class Program 
{ 
    static void Main() { } 

    static readonly object sync = new object(); 

    static int GetValue() { return 5; } 

    static int ReturnInside() 
    { 
     lock (sync) 
     { 
      return GetValue(); 
     } 
    } 

    static int ReturnOutside() 
    { 
     int val; 
     lock (sync) 
     { 
      val = GetValue(); 
     } 
     return val; 
    } 
} 

(ध्यान दें मैं खुशी से लोगों का तर्क होता है कि उस ReturnInside एक सरल/सी # के क्लीनर सा है)

और (IL को देखो रिलीज़ मोड आदि):

.method private hidebysig static int32 ReturnInside() cil managed 
{ 
    .maxstack 2 
    .locals init (
     [0] int32 CS$1$0000, 
     [1] object CS$2$0001) 
    L_0000: ldsfld object Program::sync 
    L_0005: dup 
    L_0006: stloc.1 
    L_0007: call void [mscorlib]System.Threading.Monitor::Enter(object) 
    L_000c: call int32 Program::GetValue() 
    L_0011: stloc.0 
    L_0012: leave.s L_001b 
    L_0014: ldloc.1 
    L_0015: call void [mscorlib]System.Threading.Monitor::Exit(object) 
    L_001a: endfinally 
    L_001b: ldloc.0 
    L_001c: ret 
    .try L_000c to L_0014 finally handler L_0014 to L_001b 
} 

method private hidebysig static int32 ReturnOutside() cil managed 
{ 
    .maxstack 2 
    .locals init (
     [0] int32 val, 
     [1] object CS$2$0000) 
    L_0000: ldsfld object Program::sync 
    L_0005: dup 
    L_0006: stloc.1 
    L_0007: call void [mscorlib]System.Threading.Monitor::Enter(object) 
    L_000c: call int32 Program::GetValue() 
    L_0011: stloc.0 
    L_0012: leave.s L_001b 
    L_0014: ldloc.1 
    L_0015: call void [mscorlib]System.Threading.Monitor::Exit(object) 
    L_001a: endfinally 
    L_001b: ldloc.0 
    L_001c: ret 
    .try L_000c to L_0014 finally handler L_0014 to L_001b 
} 

तो आईएल स्तर वे कर रहे हैं पर [दे या कुछ नाम ले] समान (मैं कुछ ;-p) सीखा है। इस तरह, एकमात्र समझदार तुलना स्थानीय कोडिंग शैली का (अत्यधिक व्यक्तिपरक) कानून है ... मैं सादगी के लिए ReturnInside पसंद करता हूं, लेकिन मैं इसके बारे में उत्साहित नहीं होगा।

+1

आप आईएल कैसे प्राप्त करते हैं कोड सर? –

+11

मैंने (फ्री और उत्कृष्ट) लाल गेट के .NET परावर्तक (था: लुट्ज रोडर का .NET परावर्तक) का उपयोग किया था, लेकिन आईएलडीएएसएम भी ऐसा करेगा। –

+1

सबसे शक्तिशाली पहलुओं में से एक परावर्तक यह है कि आप वास्तव में आईएल को अपनी पसंदीदा भाषा (सी #, वीबी, डेल्फी, एमसी ++, क्रोम, आदि) में –

34

इससे कोई फर्क नहीं पड़ता; वे दोनों संकलक द्वारा एक ही चीज़ में अनुवादित हैं।

स्पष्ट करने के लिए, या तो प्रभावी रूप से निम्नलिखित अर्थ विज्ञान के साथ कुछ करने के लिए अनुवाद किया है:

T myData; 
Monitor.Enter(mutex) 
try 
{ 
    myData= // something 
} 
finally 
{ 
    Monitor.Exit(mutex); 
} 

return myData; 
+1

ठीक है, यह कोशिश/अंत में सच है - हालांकि, लॉक के बाहर की वापसी के लिए अभी भी अतिरिक्त स्थानीय लोगों की आवश्यकता है जिन्हें अनुकूलित नहीं किया जा सकता है - और अधिक कोड लेता है ... –

+2

आप किसी प्रयास ब्लॉक से वापस नहीं आ सकते; इसे ".leave" सेशन-कोड के साथ समाप्त होना चाहिए। इसलिए उत्सर्जित सीआईएल किसी भी मामले में समान होना चाहिए। –

+2

आप सही हैं - मैंने अभी आईएल देखा है (अपडेटेड पोस्ट देखें)। मैंने कुछ सीखा ;- –

0

बाहर क्लीनर लग रहा है।

+0

क्या होता है जब वर्तमान थ्रेड लॉक से बाहर हो जाता है और अगला थ्रेड लाइन में इंतजार कर रहा है, तो लौटने से पहले वापस आने वाले वेरिएबल को बदलता है? –

1

साथी डेवलपर्स के कोड को पढ़ने में आसान बनाने के लिए मैं पहला विकल्प सुझाऊंगा।

5

तो लगता है कि ताला बाहर बेहतर लग रहा है, लेकिन सावधान यदि आप करने के लिए कोड को बदलने अंत हो:

return f(...) 

च() ताला तो यह स्पष्ट रूप से आयोजित अंदर होने की जरूरत है के साथ कहा जा करने की आवश्यकता है ताला, स्थिरता के लिए ताला के अंदर रिटर्न रखने के रूप में समझ में आता है।

4

यह निर्भर करता है,

मैं यहाँ अनाज के खिलाफ जाने के लिए जा रहा हूँ। मैं आम तौर पर ताला के अंदर वापस आऊंगा।

आमतौर पर परिवर्तनीय mydata एक स्थानीय चर है। जब मैं उन्हें प्रारंभ करता हूं तो मुझे स्थानीय चर घोषित करने का शौक है। मेरे पास लॉक के बाहर मेरे रिटर्न वैल्यू को शुरू करने के लिए शायद ही कभी डेटा है।

तो आपकी तुलना वास्तव में त्रुटिपूर्ण है। जबकि आदर्श रूप से दोनों विकल्पों के बीच का अंतर आपके जैसा लिखा गया होगा, जो प्रतीत होता है कि यह मामला 1 मामला है, प्रैक्टिस में यह थोड़ा उलझन में है।

void example() { 
    int myData; 
    lock (foo) { 
     myData = ...; 
    } 
    return myData 
} 

बनाम

void example() { 
    lock (foo) { 
     return ...; 
    } 
} 

मैं मामले 2 विशेष रूप से छोटे-छोटे स्निपेट के लिए पेंच को पढ़ने के लिए काफी आसान है और कठिन हो सकता है, लगता है।

30

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

+3

यह सही है, एक बिंदु अन्य उत्तरदाताओं को याद आ रही है। उनके द्वारा बनाए गए सरल नमूने एक ही आईएल उत्पन्न कर सकते हैं, लेकिन यह वास्तविक जीवन परिदृश्यों के लिए ऐसा नहीं है। –

+4

मुझे आश्चर्य हुआ कि अन्य उत्तरों इस –

+3

के बारे में बात नहीं करते हैं इस नमूने में वे वापसी मूल्य को स्टोर करने के लिए एक स्टैक वैरिएबल का उपयोग करने के बारे में बात कर रहे हैं, यानी लॉक के बाहर केवल बयान और निश्चित रूप से परिवर्तनीय घोषणा। एक और थ्रेड में एक और ढेर होना चाहिए और इस प्रकार कोई नुकसान नहीं हो सका, क्या मैं सही हूँ? –

1

इसके लायक होने के लिए, documentation on MSDN में लॉक के अंदर से लौटने का एक उदाहरण है। यहां पर दिए गए अन्य उत्तरों से, यह बहुत समान आईएल प्रतीत होता है, लेकिन मेरे लिए, यह लॉक के अंदर से वापस लौटने के लिए सुरक्षित लगता है क्योंकि तब आप किसी अन्य थ्रेड द्वारा ओवरराइट किए जाने वाले रिटर्न वैरिएबल का जोखिम नहीं चलाते हैं। हमेशा

0

lock() return <expression> बयान:

1) ताला

2) निर्दिष्ट प्रकार के मूल्य के लिए बनाता है स्थानीय (धागा सुरक्षित) स्टोर में प्रवेश करेंगे,

3) मूल्य के साथ दुकान भरता है <expression> द्वारा दिया,

4) से बाहर निकलें ताला

5) की दुकान वापस जाएँ।

इसका मतलब है कि लॉक स्टेटमेंट से लौटाया गया मूल्य, हमेशा लौटने से पहले "पकाया जाता है"।

lock() return के बारे में चिंता मत करो, यहाँ किसी को भी सुन नहीं है))

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