[STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); // var context = SynchronizationContext.Current; if (context == null) MessageBox.Show("No context for this thread"); else MessageBox.Show("We got a context"); // Form1 form = new Form1(); // context = SynchronizationContext.Current; if (context == null) MessageBox.Show("No context for this thread"); else MessageBox.Show("We got a context"); if (context == null) MessageBox.Show("No context for this thread"); Application.Run(new Form1()); }
private void InitializeComponent() { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1)); this.mListBox = new System.Windows.Forms.ListBox(); this.toolStrip1 = new System.Windows.Forms.ToolStrip(); this.mToolStripButtonThreads = new System.Windows.Forms.ToolStripButton(); this.toolStrip1.SuspendLayout(); this.SuspendLayout(); // // mListBox // this.mListBox.Dock = System.Windows.Forms.DockStyle.Fill; this.mListBox.FormattingEnabled = true; this.mListBox.Location = new System.Drawing.Point(0, 0); this.mListBox.Name = "mListBox"; this.mListBox.Size = new System.Drawing.Size(284, 264); this.mListBox.TabIndex = 0; // // toolStrip1 // this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.mToolStripButtonThreads}); this.toolStrip1.Location = new System.Drawing.Point(0, 0); this.toolStrip1.Name = "toolStrip1"; this.toolStrip1.Size = new System.Drawing.Size(284, 25); this.toolStrip1.TabIndex = 1; this.toolStrip1.Text = "toolStrip1"; // // mToolStripButtonThreads // this.mToolStripButtonThreads.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; this.mToolStripButtonThreads.Image = ((System.Drawing.Image) (resources.GetObject("mToolStripButtonThreads.Image"))); this.mToolStripButtonThreads.ImageTransparentColor = System.Drawing.Color.Magenta; this.mToolStripButtonThreads.Name = "mToolStripButtonThreads"; this.mToolStripButtonThreads.Size = new System.Drawing.Size(148, 22); this.mToolStripButtonThreads.Text = "Press Here to start threads"; this.mToolStripButtonThreads.Click += new System.EventHandler(this.mToolStripButtonThreads_Click); // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(284, 264); this.Controls.Add(this.toolStrip1); this.Controls.Add(this.mListBox); this.Name = "Form1"; this.Text = "Form1"; this.toolStrip1.ResumeLayout(false); this.toolStrip1.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); } #endregion private System.Windows.Forms.ListBox mListBox; private System.Windows.Forms.ToolStrip toolStrip1; private System.Windows.Forms.ToolStripButton mToolStripButtonThreads; }
public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void mToolStripButtonThreads_Click(object sender, EventArgs e) { // id int id = Thread.CurrentThread.ManagedThreadId; Trace.WriteLine("mToolStripButtonThreads_Click thread: " + id); // // (UI ), uiContext // UI // ( ) // , . SynchronizationContext uiContext = SynchronizationContext.Current; // Run Thread thread = new Thread(Run); // , // UI thread.Start(uiContext); } private void Run(object state) { // id int id = Thread.CurrentThread.ManagedThreadId; Trace.WriteLine("Run thread: " + id); // state' SynchronizationContext uiContext = state as SynchronizationContext; for (int i = 0; i < 1000; i++) { // // - Thread.Sleep(10); // UI , // UpdateUI, UpdateUI // UI uiContext.Post(UpdateUI, "line " + i.ToString()); } } /// <summary> /// UI /// </summary> private void UpdateUI(object state) { int id = Thread.CurrentThread.ManagedThreadId; Trace.WriteLine("UpdateUI thread:" + id); string text = state as string; mListBox.Items.Add(text); } }
SynchronizationContext uiContext = SynchronizationContext.Current;
// SynchronizationContext uiContext = state as SynchronizationContext;
public virtual void Send(SendOrPostCallback d, object state);
uiContext.Send(UpdateUI, "line " + i.ToString());
private void UpdateUI(object state) { int id = Thread.CurrentThread.ManagedThreadId; Trace.WriteLine("UpdateUI thread:" + id); string text = state as string; mListBox.Items.Add(text); }
mToolStripButtonThreads_Click thread: 10 Run thread: 3 UpdateUI thread:10 UpdateUI thread:10 UpdateUI thread:10 UpdateUI thread:10 UpdateUI thread:10 UpdateUI thread:10 UpdateUI thread:10 UpdateUI thread:10 UpdateUI thread:10 UpdateUI thread:10 UpdateUI thread:10 UpdateUI thread:10 UpdateUI thread:10 UpdateUI thread:10 UpdateUI thread:10 ... (x1000 times)
private void Run(object state) { // id int id = Thread.CurrentThread.ManagedThreadId; Trace.WriteLine("Run thread: " + id); // SynchronizationContext uiContext = state as SynchronizationContext; for (int i = 0; i < 1000; i++) { Trace.WriteLine("Loop " + i.ToString()); // Thread.Sleep(10); // UI try { uiContext.Send(UpdateUI, "line " + i.ToString()); } catch (Exception e) { Trace.WriteLine(e.Message); } } } /// <summary> /// UI /// </summary> private void UpdateUI(object state) { throw new Exception("Boom"); }
// Summary: // Provides the basic functionality for propagating a synchronization context // in various synchronization models. public class SynchronizationContext { // Summary: // Creates a new instance of the System.Threading.SynchronizationContext class. public SynchronizationContext(); // Summary: // Gets the synchronization context for the current thread. // // Returns: // A System.Threading.SynchronizationContext object representing the current // synchronization context. public static SynchronizationContext Current { get; } // Summary: // When overridden in a derived class, creates a copy of the synchronization // context. // // Returns: // A new System.Threading.SynchronizationContext object. public virtual SynchronizationContext CreateCopy(); // // Summary: // Determines if wait notification is required. // // Returns: // true if wait notification is required; otherwise, false. public bool IsWaitNotificationRequired(); // // Summary: // When overridden in a derived class, responds to the notification that an // operation has completed. public virtual void OperationCompleted(); // // Summary: // When overridden in a derived class, responds to the notification that an // operation has started. public virtual void OperationStarted(); // // Summary: // When overridden in a derived class, dispatches an asynchronous message to // a synchronization context. // // Parameters: // d: // The System.Threading.SendOrPostCallback delegate to call. // // state: // The object passed to the delegate. public virtual void Post(SendOrPostCallback d, object state); // // Summary: // When overridden in a derived class, dispatches a synchronous message to a // synchronization context. // // Parameters: // d: // The System.Threading.SendOrPostCallback delegate to call. // // state: // The object passed to the delegate. public virtual void Send(SendOrPostCallback d, object state); // // Summary: // Sets the current synchronization context. // // Parameters: // syncContext: // The System.Threading.SynchronizationContext object to be set. public static void SetSynchronizationContext(SynchronizationContext syncContext); // // Summary: // Sets notification that wait notification is required and prepares the callback // method so it can be called more reliably when a wait occurs. protected void SetWaitNotificationRequired(); // // Summary: // Waits for any or all the elements in the specified array to receive a signal. // // Parameters: // waitHandles: // An array of type System.IntPtr that contains the native operating system // handles. // // waitAll: // true to wait for all handles; false to wait for any handle. // // millisecondsTimeout: // The number of milliseconds to wait, or System.Threading.Timeout.Infinite // (-1) to wait indefinitely. // // Returns: // The array index of the object that satisfied the wait. [PrePrepareMethod] [CLSCompliant(false)] public virtual int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout); // // Summary: // Helper function that waits for any or all the elements in the specified array // to receive a signal. // // Parameters: // waitHandles: // An array of type System.IntPtr that contains the native operating system // handles. // // waitAll: // true to wait for all handles; false to wait for any handle. // // millisecondsTimeout: // The number of milliseconds to wait, or System.Threading.Timeout.Infinite // (-1) to wait indefinitely. // // Returns: // The array index of the object that satisfied the wait. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] [PrePrepareMethod] [CLSCompliant(false)] protected static int WaitHelper(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout); }
// // Summary: // // When overridden in a derived class, dispatches an asynchronous message to // a synchronization context. // // Parameters: // d: // The System.Threading.SendOrPostCallback delegate to call. // // state: // The object passed to the delegate. public virtual void Post(SendOrPostCallback d, object state);
class Program { private static SynchronizationContext mT1 = null; static void Main(string[] args) { // id int id = Thread.CurrentThread.ManagedThreadId; Console.WriteLine("Main thread is " + id); // var context = new SynchronizationContext(); // SynchronizationContext.SetSynchronizationContext(context); // Thread t1 = new Thread(new ParameterizedThreadStart(Run1)); t1.Start(SynchronizationContext.Current); Console.ReadLine(); } static private void Run1(object state) { int id = Thread.CurrentThread.ManagedThreadId; Console.WriteLine("Run1 Thread ID: " + id); // var context = state as SynchronizationContext; // context.Send(DoWork, null); while (true) Thread.Sleep(10000000); } static void DoWork(object state) { int id = Thread.CurrentThread.ManagedThreadId; Console.WriteLine("DoWork Thread ID:" + id); } }
Main thread is 10 Run1 Thread ID: 11 DoWork Thread ID:11
public bool InvokeRequired { get { using (new MultithreadSafeCallScope()) { HandleRef hwnd; if (IsHandleCreated) { hwnd = new HandleRef(this, Handle); } else { Control marshalingControl = FindMarshalingControl(); if (!marshalingControl.IsHandleCreated) { return false; } hwnd = new HandleRef(marshalingControl, marshalingControl.Handle); } int pid; int hwndThread = SafeNativeMethods.GetWindowThreadProcessId(hwnd, out pid); int currentThread = SafeNativeMethods.GetCurrentThreadId(); return(hwndThread != currentThread); } } }
private Object MarshaledInvoke(Control caller, Delegate method, Object[] args, bool synchronous) { // Marshaling an invoke occurs in three steps: // // 1. Create a ThreadMethodEntry that contains the packet of information // about this invoke. This TME is placed on a linked list of entries because // we have a gap between the time we PostMessage and the time it actually // gets processed, and this gap may allow other invokes to come in. Access // to this linked list is always synchronized. // // 2. Post ourselves a message. Our caller has already determined the // best control to call us on, and we should almost always have a handle. // // 3. If we're synchronous, wait for the message to get processed. We don't do // a SendMessage here so we're compatible with OLE, which will abort many // types of calls if we're within a SendMessage. // if (!IsHandleCreated) { throw new InvalidOperationException(SR.GetString(SR.ErrorNoMarshalingThread)); } // We have to demand unmanaged code permission here for the control hosted in // the browser case. Without this check, we will expose a security hole, because // ActiveXImpl.OnMessage() will assert unmanaged code for everyone as part of // its implementation. // The right fix is to remove the Assert() on top of the ActiveXImpl class, and // visit each method to see if it needs unmanaged code permission, and if so, add // the permission just to that method(s). // ActiveXImpl activeXImpl = (ActiveXImpl)Properties.GetObject(PropActiveXImpl); if (activeXImpl != null) { IntSecurity.UnmanagedCode.Demand(); } // We don't want to wait if we're on the same thread, or else we'll deadlock. // It is important that syncSameThread always be false for asynchronous calls. // bool syncSameThread = false; int pid; // ignored if (SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(this, Handle), out pid) == SafeNativeMethods.GetCurrentThreadId()) { if (synchronous) syncSameThread = true; } // Store the compressed stack information from the thread that is calling the Invoke() // so we can assign the same security context to the thread that will actually execute // the delegate being passed. // ExecutionContext executionContext = null; if (!syncSameThread) { executionContext = ExecutionContext.Capture(); } ThreadMethodEntry tme = new ThreadMethodEntry(caller, this, method, args, synchronous, executionContext); lock (this) { if (threadCallbackList == null) { threadCallbackList = new Queue(); } } lock (threadCallbackList) { if (threadCallbackMessage == 0) { threadCallbackMessage = SafeNativeMethods.RegisterWindowMessage(Application.WindowMessagesVersion + "_ThreadCallbackMessage"); } threadCallbackList.Enqueue(tme); } if (syncSameThread) { InvokeMarshaledCallbacks(); } else { // UnsafeNativeMethods.PostMessage(new HandleRef(this, Handle), threadCallbackMessage, IntPtr.Zero, IntPtr.Zero); } if (synchronous) { if (!tme.IsCompleted) { WaitForWaitHandle(tme.AsyncWaitHandle); } if (tme.exception != null) { throw tme.exception; } return tme.retVal; } else { return(IAsyncResult)tme; } }
namespace System.Threading { using Microsoft.Win32.SafeHandles; using System.Security.Permissions; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Runtime.ConstrainedExecution; using System.Reflection; internal struct SynchronizationContextSwitcher : IDisposable { internal SynchronizationContext savedSC; internal SynchronizationContext currSC; internal ExecutionContext _ec; public override bool Equals(Object obj) { if (obj == null || !(obj is SynchronizationContextSwitcher)) return false; SynchronizationContextSwitcher sw = (SynchronizationContextSwitcher)obj; return (this.savedSC == sw.savedSC && this.currSC == sw.currSC && this._ec == sw._ec); } public override int GetHashCode() { return ToString().GetHashCode(); } public static bool operator ==(SynchronizationContextSwitcher c1, SynchronizationContextSwitcher c2) { return c1.Equals(c2); } public static bool operator !=(SynchronizationContextSwitcher c1, SynchronizationContextSwitcher c2) { return !c1.Equals(c2); } void IDisposable.Dispose() { Undo(); } internal bool UndoNoThrow() { if (_ec == null) { return true; } try { Undo(); } catch { return false; } return true; } public void Undo() { if (_ec == null) { return; } ExecutionContext executionContext = Thread.CurrentThread.GetExecutionContextNoCreate(); if (_ec != executionContext) { throw new InvalidOperationException(Environment.GetResourceString( "InvalidOperation_SwitcherCtxMismatch")); } if (currSC != _ec.SynchronizationContext) { throw new InvalidOperationException(Environment.GetResourceString( "InvalidOperation_SwitcherCtxMismatch")); } BCLDebug.Assert(executionContext != null, " ExecutionContext can't be null"); // restore the Saved Sync context as current executionContext.SynchronizationContext = savedSC; // can't reuse this anymore _ec = null; } } public delegate void SendOrPostCallback(Object state); [Flags] enum SynchronizationContextProperties { None = 0, RequireWaitNotification = 0x1 }; public class SynchronizationContext { SynchronizationContextProperties _props = SynchronizationContextProperties.None; public SynchronizationContext() { } // protected so that only the derived sync // context class can enable these flags protected void SetWaitNotificationRequired() { // Prepare the method so that it can be called // in a reliable fashion when a wait is needed. // This will obviously only make the Wait reliable // if the Wait method is itself reliable. The only thing // preparing the method here does is to ensure there // is no failure point before the method execution begins. RuntimeHelpers.PrepareDelegate(new WaitDelegate(this.Wait)); _props |= SynchronizationContextProperties.RequireWaitNotification; } public bool IsWaitNotificationRequired() { return ((_props & SynchronizationContextProperties.RequireWaitNotification) != 0); } public virtual void Send(SendOrPostCallback d, Object state) { d(state); } public virtual void Post(SendOrPostCallback d, Object state) { ThreadPool.QueueUserWorkItem(new WaitCallback(d), state); } public virtual void OperationStarted() { } public virtual void OperationCompleted() { } // Method called when the CLR does a wait operation public virtual int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout) { return WaitHelper(waitHandles, waitAll, millisecondsTimeout); } // Static helper to which the above method // can delegate to in order to get the default // COM behavior. protected static extern int WaitHelper(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout); // set SynchronizationContext on the current thread public static void SetSynchronizationContext(SynchronizationContext syncContext) { SetSynchronizationContext(syncContext, Thread.CurrentThread.ExecutionContext.SynchronizationContext); } internal static SynchronizationContextSwitcher SetSynchronizationContext(SynchronizationContext syncContext, SynchronizationContext prevSyncContext) { // get current execution context ExecutionContext ec = Thread.CurrentThread.ExecutionContext; // create a switcher SynchronizationContextSwitcher scsw = new SynchronizationContextSwitcher(); RuntimeHelpers.PrepareConstrainedRegions(); try { // attach the switcher to the exec context scsw._ec = ec; // save the current sync context using the passed in value scsw.savedSC = prevSyncContext; // save the new sync context also scsw.currSC = syncContext; // update the current sync context to the new context ec.SynchronizationContext = syncContext; } catch { // Any exception means we just restore the old SyncCtx scsw.UndoNoThrow(); //No exception will be thrown in this Undo() throw; } // return switcher return scsw; } // Get the current SynchronizationContext on the current thread public static SynchronizationContext Current { get { ExecutionContext ec = Thread.CurrentThread.GetExecutionContextNoCreate(); if (ec != null) return ec.SynchronizationContext; return null; } } // helper to Clone this SynchronizationContext, public virtual SynchronizationContext CreateCopy() { // the CLR dummy has an empty clone function - no member data return new SynchronizationContext(); } private static int InvokeWaitMethodHelper(SynchronizationContext syncContext, IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout) { return syncContext.Wait(waitHandles, waitAll, millisecondsTimeout); } } }
public virtual void Send(SendOrPostCallback d, Object state) { d(state); } public virtual void Post(SendOrPostCallback d, Object state) { ThreadPool.QueueUserWorkItem(new WaitCallback(d), state); }
using(var processor = new Processor<int>(handler, exceptionHandler, completedHandler)) { for(int i=0;i<1000000; i++) processor.Push(i); }
Source: https://habr.com/ru/post/232169/
All Articles