C# 处理单个线程上多个线程的请求-.NET内核

C# 处理单个线程上多个线程的请求-.NET内核,c#,multithreading,.net-core,C#,Multithreading,.net Core,抱歉,如果这个问题已经有了答案,但如果有,我在这个网站上找不到 首先-这个问题是针对.NET核心的(撰写本文时为v1.1.0) 我有一个第三方程序集,它只处理来自同一线程的请求。此程序集是RabbitMQ库以及可能相关或不相关的问题的详细信息。基本上,我有多个线程可以调用这个程序集,但是如果请求来自不同的线程,它就会抛出一个异常 所以,为了避免这个问题,我试图创建一个被阻塞的线程,这样它就不会过期,并且必须在这个线程上处理对这个程序集的所有调用 我的第一次尝试是在被阻止的线程上创建一个事件并订阅

抱歉,如果这个问题已经有了答案,但如果有,我在这个网站上找不到

首先-这个问题是针对.NET核心的(撰写本文时为v1.1.0)

我有一个第三方程序集,它只处理来自同一线程的请求。此程序集是RabbitMQ库以及可能相关或不相关的问题的详细信息。基本上,我有多个线程可以调用这个程序集,但是如果请求来自不同的线程,它就会抛出一个异常

所以,为了避免这个问题,我试图创建一个被阻塞的线程,这样它就不会过期,并且必须在这个线程上处理对这个程序集的所有调用

我的第一次尝试是在被阻止的线程上创建一个事件并订阅该事件。然后,任何其他线程都会开始调用此事件,我认为可以在正确的线程上获取此事件,这样我就可以实现在单个线程上处理第三方程序集请求的愿望

我现在(痛苦地)明白:(

演示问题的示例:

public class Program
{
    public static void Main(string[] args)
    {
        Program program = new Program();
        ManualResetEvent resetEvent = new ManualResetEvent(false);
        program.StartNewThreadToBeCalled(resetEvent);

        program.CallBobMultipleTimes(resetEvent);

        Console.ReadLine();
    }

    private void CallBobMultipleTimes(ManualResetEvent resetEvent)
    {
         resetEvent.WaitOne();
         for(int i=0 ; i<100 ; i++)
            ThreadPool.QueueUserWorkItem(x=>CallBob(null, null)); //Can't BeginInvoke in .NET Core
    }

    private void StartNewThreadToBeCalled(ManualResetEvent resetEvent)
    {
        ThreadPool.QueueUserWorkItem(x=>
        {   
            Bob bob = new Bob();

            CallBob += (obj, e)=> bob.InvokeMeOnOneThreadOnly();
            resetEvent.Set();                
            ManualResetEvent mre = new ManualResetEvent(false);
            mre.WaitOne();  //Real implementation will block forever - this should be the only thread handles the processing of requests.
        });
    }

    public event EventHandler CallBob;
}

public class Bob
{
    private List<int> ThreadIdentifiers = new List<int>();
    private static object SyncObject = new object();


    public void InvokeMeOnOneThreadOnly()
    {   
        lock(SyncObject)
        {
            int currentThreadId = Thread.CurrentThread.ManagedThreadId;
            if(ThreadIdentifiers.Any())
            {
                if(!ThreadIdentifiers.Contains(currentThreadId))
                   Console.WriteLine("Don't call me from multiple threads!");
            }
            else
                ThreadIdentifiers.Add(currentThreadId);
        }
    }
}
公共类程序
{
公共静态void Main(字符串[]args)
{
程序=新程序();
ManualResetEvent resetEvent=新的ManualResetEvent(错误);
program.StartNewThreadToBeCalled(重置事件);
program.CallBobMultipleTimes(重置事件);
Console.ReadLine();
}
私有无效CallBobMultipleTimes(手动重置事件重置事件)
{
resetEvent.WaitOne();
for(int i=0;iCallBob(null,null));//无法在.NET核心中启动
}
私有void StartNewThreadToBeCalled(手动重置事件重置事件)
{
ThreadPool.QueueUserWorkItem(x=>
{   
鲍勃=新鲍勃();
CallBob+=(obj,e)=>bob.invokeMeonneThreadOnly();
resetEvent.Set();
ManualResetEvent mre=新的ManualResetEvent(错误);
mre.WaitOne();//真正的实现将永远阻塞-这应该是处理请求的唯一线程。
});
}
公共事件处理程序CallBob;
}
公开课鲍勃
{
私有列表ThreadIdentifiers=新列表();
私有静态对象SyncObject=新对象();
public void invokeMeonneThreadOnly()
{   
锁定(同步对象)
{
int currentThreadId=Thread.CurrentThread.ManagedThreadId;
if(ThreadIdentifiers.Any())
{
如果(!ThreadIdentifiers.Contains(currentThreadId))
WriteLine(“不要从多个线程中调用我!”);
}
其他的
ThreadIdentifiers.Add(currentThreadId);
}
}
}
我通过在concurrentQueue周围创建一个包装器来实现这一点,该包装器会在任何时候向concurrentQueue添加内容时发出通知。然后,我会在我的特殊第三方程序集线程上处理此事件,并从该队列中拾取请求,直到其耗尽为止……不确定为什么这样做会奏效,而另一种方式则不会


有没有比我找到的更好的方法对于我来说,在.NET core的单个线程上处理来自多个不同线程的多个请求?

委托
BeginInvoke
使用
threadpool
来调度
回调
,这基本上是多个产品的
生产者-消费者
问题CER和一个消费者..NET核心包括工具
IProducerConsumerCollection
可用于解决此问题


不要与
控件.BeginInvoke
(winform)和
调度程序.BeginInvoke
(WPF)混淆,它在GUI线程上对回调进行排队。

委托使用
threadpool
调度
回调
,这基本上是一个
生产者-消费者
问题,有多个生产者和一个消费者。.NET核心包括实现
IProducerConsumerCollection
可用于解决此问题


不要与
控件.BeginInvoke
(winform)和
调度程序.BeginInvoke
(WPF)混淆,将GUI线程上的回调排队。

很难从代码中看出您正在尝试执行的操作。但是,另一种方法是使用
BlockingCollection
。后台线程可以向该集合添加值,单个线程可以坐下来尝试从集合中获取值,例如:

while(continueProcessingCollection)
{
    if(blockingCollection.TryTake(out value, TimeSpan.FromSeconds(myTimeout)))
    {
        // process value, decide to toggle continueProcessingCollection
    }
}
后台线程可以向阻止集合添加新值:

blockingCollection.Add(newValue);
并且,您需要在某个地方创建blockingCollection变量:

var blockingCollection = new BlockingCollection<MyType>();
var blockingCollection=new blockingCollection();

很难从代码中看出您想要做什么。但是,另一种方法是使用
BlockingCollection
。后台线程可以向该集合添加值,单个线程可以坐下来尝试从集合中获取值,例如:

while(continueProcessingCollection)
{
    if(blockingCollection.TryTake(out value, TimeSpan.FromSeconds(myTimeout)))
    {
        // process value, decide to toggle continueProcessingCollection
    }
}
后台线程可以向阻止集合添加新值:

blockingCollection.Add(newValue);
并且,您需要在某个地方创建blockingCollection变量:

var blockingCollection = new BlockingCollection<MyType>();
var blockingCollection=new blockingCollection();

由于队列是消费者-生产者模式的标准实现,因此,让它正常工作也就不足为奇了……没有办法知道为什么“其他方式”不起作用,因为对“其他方式”没有明确的解释(“通过创建代理”不是其中之一)。如果您需要答案,您需要澄清您为“其他方式”尝试了什么或者解释一下您希望以何种方式改进队列解决方案-在当前状态下,帖子感觉太宽泛了。@Alexei我发布帖子时正要下班-所以我没有时间获得更详细的帖子,我将尝试体验一下