BlockingCollection Take()永远阻塞

时间:2018-11-02 16:29:07

标签: c# multithreading blockingcollection

我有一个使用阻塞集合的简单生产者使用者设置。在我们的应用程序使用期间,使用者处于循环中,等待使用者将项目放入集合中,然后取出该项目并将其写入串行端口。由于某种原因collection.Take()会在集合中有项目时永远阻塞。对于此应用程序,我们可能一次激活一个或多个ProducerConsumers。无论如何,它们的行为都一样。

checkLoggedInF = user => {
   this.checkLoggedInF$ && this.checkLoggedInF$.unsubscribe() 
   this.checkLoggedInF$ = interval(5000).pipe(
     switchMap(() => this.usersService.isLoggedIn(user.loginnaam).pipe(
       map(loggedIn => ({...user, loggedIn}))
     ))
   );
   return this.checkLoggedInF$;
}

运行此命令时,print语句会递增,因此我们肯定在Collection中有数据,但是无论出于何种原因,Take()都会继续阻塞。

它也不抛出异常。

Dispose()请求取消,但是我没有在这里添加。不会被称为早被叫。

我已经尝试过使用.GetConsumingEnumerable(),但它也会永远阻塞。

我启动任务错误吗?我会用完线程吗?

我已经考虑过使用BackgroundWorker代替Task,但是根据MSFT Task是首选。

谢谢。

1 个答案:

答案 0 :(得分:1)

首先,我不会尝试创建自己的生产者/消费者实现,尤其是不会阻塞的实现。使用ActionBlock可以轻松处理简单的生产者/消费者方案。 ActionBlock具有一个内部队列,多个并发生产者可以向其发布消息。 ActionbBlock将使用传递给其构造函数的worker方法在后台处理排队的消息:

class SerialWorker
{
    ActionBlock<Data>  _serialBlock;

    public SerialWorker()
    {    
        _serialBlock=new ActionBlock<Data>(data=>DoWork(data));
    }

    //The worker action can be synchronous 
    private void DoWork(Data data)
    {
    }
    //or asynchronous
    private async Task DoWorkAsync(Data data)
    {
    }


    //Producer Code
    //While the application runs :
    public void PostData(Data data)
    {
        _serialBlock.Post(someData);
    }

//When the application finishes 
//Tell the block to shut down and wait for it to process any leftover requests
    public async Task Shutdown()
    {
        _serialBlock.Complete();    
        await _serialBlock.Completion;
    }

worker方法可以是异步的,例如new ActionBlock<Data>(data=>DoWorkAsync(data))可以正常工作。这样可以使用异步方法,而不会阻塞worker本身。

新消息以ActionBlock.Post发布。当需要关闭时,应用程序应调用Complete()来通知该动作块并等待其完成。终止之前,ActionBlock将停止接收更多消息并处理仍保留在缓冲区中的任何内容。