2011-01-11 9 views
40

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

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

private void button2_Click(object sender, EventArgs e) 
{ 
    if (SynchronizationContext.Current == null) 
    { 
     Debug.Fail("SynchronizationContext.Current is null"); 
    } 

    Task.Factory.StartNew(() => 
    { 
     CallWCFWebServiceThatThrowsAnException(); 
    }) 
    .ContinueWith((t) => 
    { 

     //update the UI 
     UpdateGUI(t.Exception); 

     if (SynchronizationContext.Current == null) 
     { 
      Debug.Fail("SynchronizationContext.Current is null"); 
     } 

    }, CancellationToken.None, 
     TaskContinuationOptions.OnlyOnFaulted, 
     TaskScheduler.FromCurrentSynchronizationContext()); 
} 

क्या मुख्य थ्रेड के SynchronizationContext.Current कारण अशक्त बनने के लिए कर सकता है?

संपादित करें:

@Hans स्टैक ट्रेस के लिए कहा। संदेश यह है:

अगर यह पसंदीदा तरीका है, लेकिन यहाँ मैं कैसे SynchronizationContext का उपयोग है
 

    at MyApp.Framework.UI.Commands.AsyncCommand.HandleTaskError(Task task) in d:\sources\s2\Framework\Sources\UI\Commands\AsyncCommand.cs:line 157 
    at System.Threading.Tasks.Task.c__DisplayClassb.b__a(Object obj) 
    at System.Threading.Tasks.Task.InnerInvoke() 
    at System.Threading.Tasks.Task.Execute() 
    at System.Threading.Tasks.Task.ExecutionContextCallback(Object obj) 
    at System.Threading.ExecutionContext.runTryCode(Object userData) 
    at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData) 
    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) 
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) 
    at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot) 
    at System.Threading.Tasks.Task.ExecuteEntry(Boolean bPreventDoubleExecution) 
    at System.Threading.Tasks.SynchronizationContextTaskScheduler.PostCallback(Object obj) 
    at System.RuntimeMethodHandle._InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeType typeOwner) 
    at System.RuntimeMethodHandle.InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeType typeOwner) 
    at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks) 
    at System.Delegate.DynamicInvokeImpl(Object[] args) 
    at System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry tme) 
    at System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj) 
    at System.Threading.ExecutionContext.runTryCode(Object userData) 
    at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData) 
    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) 
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) 
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 
    at System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme) 
    at System.Windows.Forms.Control.InvokeMarshaledCallbacks() 
    at System.Windows.Forms.Control.WndProc(Message& m) 
    at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) 
    at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) 
    at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) 
    at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg) 
    at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData) 
    at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context) 
    at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context) 
    at System.Windows.Forms.Application.Run(Form mainForm) 
    at MyApp.Framework.SharedUI.ApplicationBase.InternalStart() in d:\sources\s2\Framework\Sources\UI\SharedUI\ApplicationBase.cs:line 190 
    at MyApp.Framework.SharedUI.ApplicationBase.Start() in d:\sources\s2\Framework\Sources\UI\SharedUI\ApplicationBase.cs:line 118 
    at MyApp.App1.WinUI.HDA.Main() in d:\sources\s2\App1\Sources\WinUI\HDA.cs:line 63 

+0

UpdateGUI पर ब्रेकपॉइंट सेट करें और स्टैक ट्रेस पोस्ट करें। –

+0

@ हंस: UpdateGUI() मेरे नमूना प्रोजेक्ट में है। मेरे असली प्रोजेक्ट में, विधि को हैंडलटास्क एरर() कहा जाता है। मैंने अपने प्रश्न में स्टैक ट्रेस पोस्ट किया है। – Sylvain

+2

पूरी तरह से सामान्य लग रहा है। मुझे कोई स्पष्टीकरण नहीं है कि TaskScheduler.FromCurrentSynchronizationContext() काम नहीं करता है। यही वह है जो नियंत्रण के लिए अनुसूचित जाति प्रदान करता है। इन्वोक मार्शल कॉलबैक() कॉल। यह पहले से ही एक शून्य के लिए जाँच करता है। मान लीजिए कि आप .NET 4.0 –

उत्तर

9

सुनिश्चित नहीं हैं कि जिस तरह से आप

आप निर्माता (मुख्य थ्रेड) वर्तमान संदर्भ की एक प्रतिलिपि सहेजने में, सही संदर्भ होने के बाद (??) गारंटी दी जाती है इससे कोई फर्क नहीं पड़ता कि आप किस धागे पर हैं।

_uiCtx = SynchronizationContext.Current; 

और बाद में अपने कार्य में इसका इस्तेमाल मुख्य यूआई धागा

_uiCtx.Post((o) => 
{ 
//UI Stuff goes here 
}, null); 
+3

यह निश्चित रूप से काम करेगा लेकिन यह एक कामकाज होगा। मैं यह जानना चाहता हूं कि मुख्य थ्रेड कैसे सिंक्रनाइज़ेशन कॉन्टेक्स्ट खो गया। – Sylvain

43

स्लाई, मैं ठीक उसी व्यवहार में चलाने की है जब WPF, WCF, और TPL का एक मिश्रण है के साथ बातचीत करने के लिए उपयोग किया गया। मुख्य थ्रेड का वर्तमान सिंक्रनाइज़ेशन कॉन्टेक्स्ट कुछ स्थितियों में शून्य हो जाएगा।

var context = SynchronizationContext.Current; 

// if context is null, an exception of 
// The current SynchronizationContext may not be used as a TaskScheduler. 
// will be thrown 
TaskScheduler.FromCurrentSynchronizationContext(); 

this post MSDN मंचों पर के अनुसार, इस 4.0 में TPL में इस बात की पुष्टि बग है। एक सहकर्मी 4.5 पर चल रहा है और यह व्यवहार नहीं देखता है।

हमने इसे फॉरक्रुंट सिंक्रनाइज़ेशन कॉन्टेक्स्ट का उपयोग करके मुख्य थ्रेड के साथ एक स्थिर सिंगलटन में एक टास्कशेड्यूलर बनाकर हल किया और फिर निरंतरता बनाते समय उस कार्य शेड्यूलर को हमेशा संदर्भित किया। उदाहरण के लिए

Task task = Task.Factory.StartNew(() => 
    { 
    // something 
    } 
).ContinueWith(t => 
    { 
    // ui stuff 
    }, TheSingleton.Current.UiTaskScheduler); 

यह टीपीएल में .NET 4.0 पर समस्या से बचाता है।

अद्यतन आप .net 4.5 अपने विकास मशीन पर स्थापित है, तो आप इस मुद्दे को नहीं देख सकेंगे, भले ही आप 4.0 ढांचे को लक्षित कर रहे हैं। आपके उपयोगकर्ता जिनके पास केवल 4.0 स्थापित है, अभी भी प्रभावित होंगे।

+1

मुझे इस बग का अनुभव हुआ - मैंने एक छोटा विनफॉर्म प्रोग्राम पोस्ट किया है जो इस मुद्दे को पुन: उत्पन्न करने का एक आसान तरीका दिखाता है। http://stackoverflow.com/questions/11621372/synchronizationcontext-current-is-null-in-continuation-on-the-main-ui-thread –

+1

लक्ष्यीकरण 4.5.2 यहां, अभी भी यह त्रुटि संदेश पॉप अप है। हालांकि सभी कार्यों पर नहीं ... – CularBytes

7

मैंने इसके लिए एक कक्षा बनाई है। यह इस तरह दिखता है:

public class UIContext 
{ 
    private static TaskScheduler m_Current; 

    public static TaskScheduler Current 
    { 
     get { return m_Current; } 
     private set { m_Current = value; } 
    } 

    public static void Initialize() 
    { 
     if (Current != null) 
      return; 

     if (SynchronizationContext.Current == null) 
      SynchronizationContext.SetSynchronizationContext(new SynchronizationContext()); 

     Current = TaskScheduler.FromCurrentSynchronizationContext(); 
    } 
} 

मेरी अनुप्रयोग के प्रारंभ में मैं UIContext.Initialize()

फोन और जब मैं एक काम में इसकी जरूरत मैं सिर्फ TaskScheduler रूप UIContext.Current डाल दिया।

Task.Factory.StartNew(() => 
{ 
    //Your code here 
}, CancellationToken.None, TaskCreationOptions.None, UIContext.Current); 
+0

एकता (5.5) परियोजना पर बहुत अच्छा काम किया जो इस सटीक समस्या का सामना कर रहा था। धन्यवाद! – jeromeyers

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

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