非同期関数を呼び出す同じスレッドでコールバックメソッドを実行する方法。 呼び出し元のスレッドがUIスレッドではないかもしれない...しかし、UIは&よろしく、 ディネッシュスレッド切り替え
スレッド切り替え
答えて
あるスレッドが別のスレッドにデリゲートの実行を開始させる魔法の弾丸はありません。ターゲットスレッドは、これを可能にするために特別に構成されなければなりません。 UIスレッドの場合、メッセージをディスパッチして処理するメッセージポンプがあります。このメッセージポンプを使用して、ISynchronizeInvoke
インターフェイス経由でマーシャリング操作を実行できます。あなたのケースでは
ISynchronizeInvoke target = someForm; // where someForm is a Form or Control
target.Invoke(
(Action)(() =>
{
MessageBox.Show("I am on the target thread");
}), null);
ワーカースレッドからそうするように指示された後、非同期関数を呼び出したスレッドは、そのスレッドで非同期的に実行するコールバックを得るためにそれに組み込まれた生産者 - 消費者機構のいくつかの種類を持っている必要があります。残念ながら、これは解決すべき小さな問題ではありません。
デリゲートを実行できるスレッドを作成する方法の1つです。
public class SynchronizeInvokeThread : ISynchronizeInvoke
{
private Thread m_Thread;
private BlockingCollection<WorkItem> m_Collection = new BlockingCollection<WorkItem>();
public SynchronizeInvokeThread()
{
m_Thread = new Thread(
() =>
{
SynchronizationContext.SetSynchronizationContext(new MySynchronizationContext(this));
while (true)
{
WorkItem wi = m_Collection.Take();
wi.Complete(wi.Method.DynamicInvoke(wi.Args));
}
});
m_Thread.Start();
}
public IAsyncResult BeginInvoke(Delegate method, object[] args)
{
var wi = new WorkItem(method, args);
m_Collection.Add(wi);
return wi;
}
public object EndInvoke(IAsyncResult result)
{
var wi = (WorkItem)result;
wi.AsyncWaitHandle.WaitOne();
return wi.Result;
}
public object Invoke(Delegate method, object[] args)
{
var wi = new WorkItem(method, args);
m_Collection.Add(wi);
wi.AsyncWaitHandle.WaitOne();
return wi.Result;
}
public bool InvokeRequired
{
get { return Thread.CurrentThread != m_Thread; }
}
private class MySynchronizationContext : SynchronizationContext
{
private ISynchronizeInvoke m_SynchronizingObject;
public MySynchronizationContext(ISynchronizeInvoke synchronizingObject)
{
m_SynchronizingObject = synchronizingObject;
}
public override void Post(SendOrPostCallback d, object state)
{
m_SynchronizingObject.BeginInvoke(d, new object[] { state });
}
public override void Send(SendOrPostCallback d, object state)
{
m_SynchronizingObject.Invoke(d, new object[] { state });
}
}
private class WorkItem : IAsyncResult
{
private Delegate m_Method;
private object[] m_Args;
private object m_Result = null;
private ManualResetEvent m_Signal = new ManualResetEvent(false);
public WorkItem(Delegate method, object[] args)
{
m_Method = method;
m_Args = args;
}
public void Complete(object result)
{
m_Result = result;
m_Signal.Set();
}
public object Result
{
get { return m_Result; }
}
public Delegate Method
{
get { return m_Method; }
}
public object[] Args
{
get { return m_Args; }
}
public object AsyncState
{
get { return null; }
}
public WaitHandle AsyncWaitHandle
{
get { return m_Signal; }
}
public bool CompletedSynchronously
{
get { return false; }
}
public bool IsCompleted
{
get { return m_Signal.WaitOne(0); }
}
}
}
このように使用できます。
ISynchronizeInvoke target = new SynchronizeInvokeThread();
target.Invoke(
(Action)(() =>
{
Console.WriteLine("I am on the target thread");
SynchronizationContext.Current.Post(
(state) =>
{
Console.WriteLine("I even have a synchronization context!");
}, null);
}), null);
更新:BlockingCollection
以下のコメントパー
.NET 4.0またはReactive Extensionsダウンロードの一部としてのみ使用可能です。このデータ構造が利用できない場合は、すでに難しいコードがさらに難しくなりました。
使用BackgroundWorkerのを..ハング
感謝すべきではありません。コールバックは所有スレッド上にあります。
コールバック後でも非同期操作を実行する必要がある場合は、WPF System.Windows.Application.Current.Dispatcher.Invoke/BeginInvokeを使用して複数のコールバックを行うことができます。WinFormsの場合は、フォームまたはコントロールインスタンス自体を呼び出して、Invoke/BeginInvokeを呼び出します。
それは、その後のBackgroundWorkerのCompletedイベントが別のスレッドで呼び出されたコンソール・アプリケーションである場合.. .. – dinesh
Brian Gideon
のように、ISynchronizeInvoke "System.ComponentModel.ISynchronizeInvoke"を使用する必要があります。別のスレッドでスレッドの実行をマーシャリングするクラスで実装します。ここでの例Media
クラス "私が実装したクラスは、Comオブジェクトとやりとりしていたので、メインスレッドでそのメソッドを実行すべきです";クラス実装のためにSystem.Threading.SynchronizationContext.Current
を使用するので、System.Threading.SynchronizationContext.Currentがnullであるため、WindowsFormsでは使用できますがコンソールアプリケーションでは使用できません。
このクラスの実行を、それを作成したスレッドにマーシャリングしたいときはいつでも、そのメソッドのInvoke
を呼び出します。我々はRunAsyncのfnctionを呼び出しているでは
public abstract class Media : ISynchronizeInvoke
{
//....
private readonly System.Threading.SynchronizationContext _currentContext = System.Threading.SynchronizationContext.Current;
private readonly System.Threading.Thread _mainThread = System.Threading.Thread.CurrentThread;
private readonly object _invokeLocker = new object();
//....
#region ISynchronizeInvoke Members
public bool InvokeRequired
{
get
{
return System.Threading.Thread.CurrentThread.ManagedThreadId != this._mainThread.ManagedThreadId;
}
}
/// <summary>
/// This method is not supported!
/// </summary>
/// <param name="method"></param>
/// <param name="args"></param>
/// <returns></returns>
[Obsolete("This method is not supported!", true)]
public IAsyncResult BeginInvoke(Delegate method, object[] args)
{
throw new NotSupportedException("The method or operation is not implemented.");
}
/// <summary>
/// This method is not supported!
/// </summary>
/// <param name="method"></param>
/// <param name="args"></param>
/// <returns></returns>
[Obsolete("This method is not supported!", true)]
public object EndInvoke(IAsyncResult result)
{
throw new NotSupportedException("The method or operation is not implemented.");
}
public object Invoke(Delegate method, object[] args)
{
if (method == null)
{
throw new ArgumentNullException("method");
}
lock (_invokeLocker)
{
object objectToGet = null;
SendOrPostCallback invoker = new SendOrPostCallback(
delegate(object data)
{
objectToGet = method.DynamicInvoke(args);
});
_currentContext.Send(new SendOrPostCallback(invoker), method.Target);
return objectToGet;
}
}
public object Invoke(Delegate method)
{
return Invoke(method, null);
}
#endregion//ISynchronizeInvoke Members
}
- 1. スレッドを切り替える
- 2. スレッドを切り替える方法
- 3. スレッドを切り替える方法はありますか?
- 4. 切り替えガレリアフルスクリーンモード
- 5. jQueryクラスの切り替えとクッキーの値の切り替え?
- 6. 他のビューの切り替えに切り替えるapp xcode
- 7. メニューの切り替えの切り替え
- 8. 数秒後に画面を切り替える(スレッド/インテント) - Android
- 9. NSXMLParser NSObjectの中サブクラスの切り替えのスレッド
- 10. androidの複数のスレッドを切り替える方法
- 11. スレッドがシステムコールを呼び出すときのコンテキスト切り替え
- 12. LINQに切り替える
- 13. エンティティデータモデルの切り替え
- 14. ビューコントローラを切り替える
- 15. javaFXの切り替えシーン
- 16. ビデオストリーミングの切り替え
- 17. カスタムリストビューでの切り替え
- 18. ダイナミックリンクに切り替える
- 19. Google Playゲームサービスマルチプレイヤーアクティビティ切り替え
- 20. キャンバスコンテキストを切り替える
- 21. ビュー間の切り替え
- 22. タブを切り替える
- 23. StringIndexOutOfBoundsExceptionページ切り替え時
- 24. モーダルビューコントローラ間の切り替え
- 25. アプリ間の切り替え
- 26. スローネスの切り替えTabItems
- 27. Outlook FormRegionの切り替え
- 28. ByteStringsへの切り替え
- 29. クラスの切り替え?
- 30. アニメーションタブバーページの切り替え
は、任意のサンプルはありますか? – dinesh
答えを更新しました。 –
@Brain Gideon: 'CustomThread'を使用すると、ターゲットスレッドでコードが呼び出されません。あなたが 'SynchronizationContext'を使ってそれを証明していないからです。 Windowsフォームでテストを実行し、 'Console.WriteLine'を' textBox1.Text = "some data"; "に置き換えてください。クロススレッド例外が発生します。また、質問タグが 'C#3.0'のところに' ConcurrentCollection'を使用していることにも注意してください。 –