C# 强制WCF使用一个线程
我有一个使用外部库的控制台应用程序。库坚持总是从同一线程调用;否则它会锁起来。(我确实试着以STA的身份运行,看看这是否能解决问题——但是没有,它确实坚持你必须始终使用同一个线程。我猜是线程本地存储…) 以前,应用程序使用原始TCP连接进行通信。但是,我最近将其更改为使用WCF。现在看来,WCF随机选择线程来运行我的代码,这导致了惊人的失败 我需要绝对100%防止这种行为发生。我不在乎我的代码在哪个线程中运行,只要它始终是同一个线程!在过去的几天里,我一直在互联网上搜索,不断地把头撞在键盘上,试图让WCF停止使用线程 我尝试过的事情:C# 强制WCF使用一个线程,c#,multithreading,wcf,C#,Multithreading,Wcf,我有一个使用外部库的控制台应用程序。库坚持总是从同一线程调用;否则它会锁起来。(我确实试着以STA的身份运行,看看这是否能解决问题——但是没有,它确实坚持你必须始终使用同一个线程。我猜是线程本地存储…) 以前,应用程序使用原始TCP连接进行通信。但是,我最近将其更改为使用WCF。现在看来,WCF随机选择线程来运行我的代码,这导致了惊人的失败 我需要绝对100%防止这种行为发生。我不在乎我的代码在哪个线程中运行,只要它始终是同一个线程!在过去的几天里,我一直在互联网上搜索,不断地把头撞在键盘上,试
强制WCF对我的东西使用单个对象,这很有用,但不能直接解决问题InstanceContextMode.Single
保证只有一个线程将并发运行,但不保证哪一个线程ConcurrencyMode=ConcurrencyMode.Single
就我所知,似乎对任何事情都没有任何影响UseSynchronizationContext
我还尝试了蛮力方法:我编写了一个类,该类创建自己的工作线程,并允许您将代码排队在该线程上执行。我单独测试了这个类,它似乎工作得很好,但是当我尝试在我的WCF应用程序中使用它时,发生了一些非常奇怪的事情。程序完美地处理第一个命令,将结果返回给客户端,然后永远挂起 这种行为毫无意义。我可以从控制台输出中看到,它没有被困在外部库中,也没有被困在我的新工作队列类中。那它到底卡在哪里了 在这一点上,我通常会开始插入更多的调试打印-除了不能将调试打印插入WCF,只能插入它调用的代码。所以我无法说出服务主机正在尝试做什么
我已经看到了关于这个话题的各种答案,所有这些答案都表明解决方案是完全不同的。有一个是关于“同步上下文”的,或多或少是不可理解的,但它似乎会做与我的工作队列类相同的事情。还有一个关于设置各种服务标志的问题——我已经做了,但没有解决。其他人建议实现自己的
ioperationbehavior
(这看起来非常复杂)
基本上在这一点上,我不知道该怎么办,我不能让这些东西工作。请帮忙-(
[控制台应用程序,自托管,NetTcpBinding
,在代码.NET 4中配置-如果有问题…]
这里是工作队列类,以防有问题:[顺便说一句,它有点大。]
公共密封类线程管理器
{
私有线程_Thread;//工作线程。
私有易失性操作_Action;//排队方法。
私有易失性对象_result;//方法结果。
private volatile bool _done;//该方法是否已完成执行?
公开作废开始()
{
_action=null;
_结果=空;
_完成=正确;
_线程=新线程(主循环);
_thread.Start();
}
public void ExecuteInWorkerThread(操作)
{
//等待队列清空。。。
Monitor.Enter(this);//锁定对象,以便我们可以检查它。
while(_action!=null)
{
Monitor.Pulse(this);//唤醒等待锁的下一个线程。
Monitor.Wait(this);//释放锁,等待脉冲(),获取锁。
}
//排队行动。。。
_行动=行动;
_完成=错误;
//等待操作完成。。。
而(!\u完成)
{
Monitor.Pulse(this);//唤醒等待锁的下一个线程。
Monitor.Wait(this);//释放锁,等待脉冲(),获取锁。
}
//工作线程现在已经完成了它的工作。
Monitor.Pulse(this);//唤醒试图将工作排队的所有线程。
Monitor.Exit(这个);//释放锁。
}
公共T执行器工作读取(功能操作)
{
ExecuteInWorkerThread(()=>{u result=action();});
return(T)_result;//如果此转换失败,则说明出现了惊人的错误!
}
//在工作线程中永远运行。
私有void MainLoop()
{
while(true)
{
//等待某个操作退出队列。。。
Monitor.Enter(this);//锁定对象以便我们可以检查它。
while(_action==null)
{
Monitor.Pulse(this);//唤醒等待锁的下一个线程。
Monitor.Wait(this);//释放锁,等待脉冲(),获取锁。
}
//出列操作。。。
var action=_action;
_action=null;
//执行操作。。。
action();//执行实际操作!
_done=true;//告诉打电话的人我们完成了。
Monitor.Pulse(this);//叫醒呼叫者。
Monitor.Exit(这个);//释放锁。
}
}
}
正如我所说,当我单独测试它时,它似乎工作得很好。[嘀咕一些关于多线程编码和确定性的东西。]当在WCF中运行时,它总是在完全相同的点失败。你需要理解
同步上下文
的概念,特别是在WCF的上下文中
public sealed class ThreadManager
{
private Thread _thread; // Worker thread.
private volatile Action _action; // Enqueued method.
private volatile object _result; // Method result.
private volatile bool _done; // Has the method finished executing?
public void Start()
{
_action = null;
_result = null;
_done = true;
_thread = new Thread(MainLoop);
_thread.Start();
}
public void ExecuteInWorkerThread(Action action)
{
// Wait for queue to empty...
Monitor.Enter(this); // Lock the object, so we can inspect it.
while (_action != null)
{
Monitor.Pulse(this); // Wake up the next thread waiting on the lock.
Monitor.Wait(this); // Release lock, wait for Pulse(), acquire lock.
}
// Enqueue action...
_action = action;
_done = false;
// Wait for action to complete...
while (! _done)
{
Monitor.Pulse(this); // Wake up the next thread waiting on the lock.
Monitor.Wait(this); // Release lock, wait for Pulse(), acquire lock.
}
// Worker thread has finished doing it's thing now.
Monitor.Pulse(this); // Wake up any threads trying to enqueue work.
Monitor.Exit(this); // Release the lock.
}
public T ExecuteInWorkerThread<T>(Func<T> action)
{
ExecuteInWorkerThread(() => { _result = action(); });
return (T) _result; // If this cast fails, something has gone spectacularly wrong!
}
// Runs forever in worker thread.
private void MainLoop()
{
while (true)
{
// Wait for an action to dequeue...
Monitor.Enter(this); // Lock object so we can inspect it.
while (_action == null)
{
Monitor.Pulse(this); // Wake up the next thread waiting on the lock.
Monitor.Wait(this); // Release lock, wait for Pulse(), acquire lock.
}
// Dequeue action...
var action = _action;
_action = null;
// Perform the action...
action(); // Do the actual action!
_done = true; // Tell the caller we're done.
Monitor.Pulse(this); // Wake the caller up.
Monitor.Exit(this); // Release the lock.
}
}
}
public class ThreadManager
{
EventLoopScheduler _scheduler = new EventLoopScheduler();
public T ExecuteInWorkerThread<T>(Func<T> action)
{
return Observable.Start(action, _scheduler).Wait();
}
}
public Task<T> ExecuteInWorkerThreadAsync<T>(Func<T> action)
{
return Observable.Start(action, _scheduler).ToTask();
}