C# 在特定线程上运行工作

C# 在特定线程上运行工作,c#,multithreading,task,C#,Multithreading,Task,我希望有一个特定的线程,任务队列和进程任务在这个单独的线程中。应用程序将根据用户使用情况生成任务,并将其排入任务队列。然后,单独的线程处理这些任务。即使队列为空,保持线程活动并将其用于处理排队的任务也是至关重要的 我用BlockingCollection尝试了几个TaskScheduler的实现,并将并发性限制为仅一个线程,但当队列变空且任务由另一个线程处理时,线程似乎会被释放 你能至少向我介绍一些如何实现这一目标的信息来源吗 tl;博士 试图将一个特定线程限制为处理动态添加到队列中的任务 编辑

我希望有一个特定的线程,任务队列和进程任务在这个单独的线程中。应用程序将根据用户使用情况生成任务,并将其排入任务队列。然后,单独的线程处理这些任务。即使队列为空,保持线程活动并将其用于处理排队的任务也是至关重要的

我用
BlockingCollection
尝试了几个
TaskScheduler
的实现,并将并发性限制为仅一个线程,但当队列变空且任务由另一个线程处理时,线程似乎会被释放

你能至少向我介绍一些如何实现这一目标的信息来源吗

tl;博士 试图将一个特定线程限制为处理动态添加到队列中的任务

编辑1:

这是一个实验性的web应用程序,使用WCF和.NET framework 4.6。在WCF库中,我试图用单线程处理任务实现这种行为。这一个线程必须使用外部dll库初始化prolog,然后使用prolog。若进程中使用了其他线程,库将抛出
AccessViolationException
。我做了一些研究,这很可能是因为库中的线程管理不好。我有一个到处都有锁的实现,它可以工作。我现在尝试重新实现并使其异步,这样我就不会用锁阻塞主线程


我不在电脑旁,但今天晚些时候回家时,我会提供一些代码。

你的方法似乎很好,所以你可能只是犯了一个小小的愚蠢错误

实际上,制作一个简单的自定义任务调度器非常容易。对于您的情况:

void Main()
{
  var cts = new CancellationTokenSource();
  var myTs = new SingleThreadTaskScheduler(cts.Token);

  myTs.Schedule(() => 
   { Print("Init start"); Thread.Sleep(1000); Print("Init done"); });
  myTs.Schedule(() => Print("Work 1"));   
  myTs.Schedule(() => Print("Work 2"));
  myTs.Schedule(() => Print("Work 3"));
  var lastOne = myTs.Schedule(() => Print("Work 4"));

  Print("Starting TS");
  myTs.Start();

  // Wait for all of them to complete...
  lastOne.GetAwaiter().GetResult();

  Thread.Sleep(1000);

  // And try to schedule another
  myTs.Schedule(() => Print("After emptied")).GetAwaiter().GetResult();

  // And shutdown; it's also pretty useful to have the 
  // TaskScheduler return a "complete task" to await
  myTs.Complete();

  Print("On main thread again");
}

void Print(string str)
{
  Console.WriteLine("{0}: {1}", Thread.CurrentThread.ManagedThreadId, str);
  Thread.Sleep(100);
}

public sealed class SingleThreadTaskScheduler : TaskScheduler
{
  [ThreadStatic]
  private static bool isExecuting;
  private readonly CancellationToken cancellationToken;

  private readonly BlockingCollection<Task> taskQueue;

  public SingleThreadTaskScheduler(CancellationToken cancellationToken)
  {
      this.cancellationToken = cancellationToken;
      this.taskQueue = new BlockingCollection<Task>();
  }

  public void Start()
  {
      new Thread(RunOnCurrentThread) { Name = "STTS Thread" }.Start();
  }

  // Just a helper for the sample code
  public Task Schedule(Action action)
  {
      return 
          Task.Factory.StartNew
              (
                  action, 
                  CancellationToken.None, 
                  TaskCreationOptions.None, 
                  this
              );
  }

  // You can have this public if you want - just make sure to hide it
  private void RunOnCurrentThread()
  {
      isExecuting = true;

      try
      {
          foreach (var task in taskQueue.GetConsumingEnumerable(cancellationToken))
          {
              TryExecuteTask(task);
          }
      }
      catch (OperationCanceledException)
      { }
      finally
      {
          isExecuting = false;
      }
  }

  // Signaling this allows the task scheduler to finish after all tasks complete
  public void Complete() { taskQueue.CompleteAdding(); }   
  protected override IEnumerable<Task> GetScheduledTasks() { return null; }

  protected override void QueueTask(Task task)
  {
      try
      {
          taskQueue.Add(task, cancellationToken);
      }
      catch (OperationCanceledException)
      { }
  }

  protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
  {
      // We'd need to remove the task from queue if it was already queued. 
      // That would be too hard.
      if (taskWasPreviouslyQueued) return false;

      return isExecuting && TryExecuteTask(task);
  }
}

请包含代码示例以突出显示问题。最重要的是,需求的根本原因是什么?我编辑了我的问题,我将在大约10小时后回家时提供代码。你是对的,愚蠢的错误-我有太多线程试图创建新的引擎对象,因为没有锁,所以更多的线程试图一次初始化prolog。谢谢你的日程安排,我有一些类似的东西,但它非常沉重和混乱,你的看起来很好和干净!谢谢!下面是一个工作示例(概念验证)
// On a new thread
try
{
  InitializeProlog();

  try
  {
    myTs.RunOnCurrentThread();
  }
  finally
  {
    ReleaseProlog();
  }
}
catch (Exception ex)
{
  // The global handler
}