从不同步的代码块中调用了对象同步方法?
这个异常提示,读起来晦涩难懂,感觉有必要解释下这句话是什么意思。
这里所说的不同步的代码块,指的是在不同的线程上运行的代码块。
对象同步方法知道是,对象的方法是同步的,应该是在同一个线程上下文中执行。
所以,总的来讲,就是说:本应该在同一个线程调用的方法,现在是在不同的线程上调用,从而引发此异常。
解决思路
针对这类问题的解决思路,就是把不同的代码块,放到同步代码块中,也就是同一个线程中调度。
具体实现方式可以有多种:
- 使用固定一个线程调用
- 使用同步上下文进行线程同步
第一种方案相对来讲,实现起来比较简单。我们可以直接开一个线程,将调用代码块,post
该线程上执行即可。
以Mutex
为例:
public class ProcessMutex
{
public ProcessMutex(string key)
{
Key = key;
}
private Mutex mutex;
public string Key { get; }
public async Task WaitOneAsync()
{
await SingleThread.RunAndWaitAsync(() =>
{
if (!Mutex.TryOpenExisting(Key, out mutex))
{
mutex = new Mutex(false, Key);
}
mutex.WaitOne();
});
}
public async Task Dispose()
{
await SingleThread.RunAndWaitAsync(() =>
{
if (mutex != null)
{
mutex.ReleaseMutex();
mutex.Dispose();
}
});
}
}
//SingleThread.RunAndWaitAsync 就是额外开启的一个常驻线程。当然,这里也可以用UI线程。
第二种方法通过使用SynchronizationContext
来实现上下文同步
在WPF
里面,上下文同步的使用方法和winform
稍微有点区别。
WPF
本身有实现System.Windows.Threading.DispatcherSynchronizationContext
,该上下文可以通过SynchronizationContext.Current
来获得。
但是,该上下文只能在UI线程上获取,因为UI线程是个常驻线程。如果是在多线程中,SynchronizationContext.Current
将为null
。
这个时候需要通过手动设置的方式进行注入:
//为当前上下文进行赋值操作
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
//需要让当前线程等待(不让线程退出)
//……省略
线程同步的更详细用法,可以参考以下博客: C# dotnet 自己实现一个线程同步上下文
欢迎转载分享,如若转载,请标注署名。
博客链接1:https://huchengv5.gitee.io/
博客链接2:https://huchengv5.github.io/
微信公众号:
本文会经常更新,请阅读原文: https://huchengv5.gitee.io//post/WPF-Mutex%E9%87%8A%E6%94%BE%E9%94%81-%E6%8F%90%E7%A4%BA-%E4%BB%8E%E4%B8%8D%E5%90%8C%E6%AD%A5%E7%9A%84%E4%BB%A3%E7%A0%81%E5%9D%97%E4%B8%AD%E8%B0%83%E7%94%A8%E4%BA%86%E5%AF%B9%E8%B1%A1%E5%90%8C%E6%AD%A5%E6%96%B9%E6%B3%95.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名胡承(包含链接: https://huchengv5.gitee.io/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 。