Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 强制WCF使用一个线程_C#_Multithreading_Wcf - Fatal编程技术网

C# 强制WCF使用一个线程

C# 强制WCF使用一个线程,c#,multithreading,wcf,C#,Multithreading,Wcf,我有一个使用外部库的控制台应用程序。库坚持总是从同一线程调用;否则它会锁起来。(我确实试着以STA的身份运行,看看这是否能解决问题——但是没有,它确实坚持你必须始终使用同一个线程。我猜是线程本地存储…) 以前,应用程序使用原始TCP连接进行通信。但是,我最近将其更改为使用WCF。现在看来,WCF随机选择线程来运行我的代码,这导致了惊人的失败 我需要绝对100%防止这种行为发生。我不在乎我的代码在哪个线程中运行,只要它始终是同一个线程!在过去的几天里,我一直在互联网上搜索,不断地把头撞在键盘上,试

我有一个使用外部库的控制台应用程序。库坚持总是从同一线程调用;否则它会锁起来。(我确实试着以STA的身份运行,看看这是否能解决问题——但是没有,它确实坚持你必须始终使用同一个线程。我猜是线程本地存储…)

以前,应用程序使用原始TCP连接进行通信。但是,我最近将其更改为使用WCF。现在看来,WCF随机选择线程来运行我的代码,这导致了惊人的失败

我需要绝对100%防止这种行为发生。我不在乎我的代码在哪个线程中运行,只要它始终是同一个线程!在过去的几天里,我一直在互联网上搜索,不断地把头撞在键盘上,试图让WCF停止使用线程

我尝试过的事情:

  • InstanceContextMode.Single
    强制WCF对我的东西使用单个对象,这很有用,但不能直接解决问题

  • 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();
}