编码任务以在特定线程上运行



我已经更新了一个使用SuperSocket连接到旧c ++服务器的旧项目。使用最新版本(从 0.7.0 => 0.8.0.8)尝试重新连接时出现异常(它说套接字在不同的线程上打开)我想要一个类来排队任务(第一次连接和重新连接)并在特定线程上运行它们。

我已经看到了这种方法,但是当我尝试运行创建的任务时出现异常

不能为以前排队到其他任务计划程序的任务调用 ExecuteTask。

这是我从上面的链接中学习的课程

public class SameThreadTaskScheduler : TaskScheduler, IDisposable
{
#region publics
public SameThreadTaskScheduler(string name)
{
scheduledTasks = new Queue<Task>();
threadName = name;
}
public override int MaximumConcurrencyLevel => 1;
public void Dispose()
{
lock (scheduledTasks)
{
quit = true;
Monitor.PulseAll(scheduledTasks);
}
}
#endregion
#region protected overrides
protected override IEnumerable<System.Threading.Tasks.Task> GetScheduledTasks()
{
lock (scheduledTasks)
{
return scheduledTasks.ToList();
}
}
protected override void QueueTask(Task task)
{
if (myThread == null)
myThread = StartThread(threadName);
if (!myThread.IsAlive)
throw new ObjectDisposedException("My thread is not alive, so this object has been disposed!");
lock (scheduledTasks)
{
scheduledTasks.Enqueue(task);
Monitor.PulseAll(scheduledTasks);
}
}
public void Queue(Task task)
{
QueueTask(task);
}
protected override bool TryExecuteTaskInline(Task task, bool task_was_previously_queued)
{
return false;
}
#endregion
private readonly Queue<System.Threading.Tasks.Task> scheduledTasks;
private Thread myThread;
private readonly string threadName;
private bool quit;
private Thread StartThread(string name)
{
var t = new Thread(MyThread) { Name = name };
using (var start = new Barrier(2))
{
t.Start(start);
ReachBarrier(start);
}
return t;
}
private void MyThread(object o)
{
Task tsk;
lock (scheduledTasks)
{
//When reaches the barrier, we know it holds the lock.
//
//So there is no Pulse call can trigger until
//this thread starts to wait for signals.
//
//It is important not to call StartThread within a lock.
//Otherwise, deadlock!
ReachBarrier(o as Barrier);
tsk = WaitAndDequeueTask();
}
for (;;)
{
if (tsk == null)
break;
TryExecuteTask(tsk);
lock (scheduledTasks)
{
tsk = WaitAndDequeueTask();
}
}
}
private Task WaitAndDequeueTask()
{
while (!scheduledTasks.Any() && !quit)
Monitor.Wait(scheduledTasks);
return quit ? null : scheduledTasks.Dequeue();
}
private static void ReachBarrier(Barrier b)
{
if (b != null)
b.SignalAndWait();
}
}

这是我如何称呼任务

public void RegisterServers()
{
sameThreadTaskScheduler.Queue(new Task(() =>
{
...something
}));

我做错了什么?

您必须启动一个任务才能将其绑定到TaskScheduler。 在您的代码中,您手动排队任务,以相反的方式执行,因此任务不会绑定到任务计划程序(或根本不绑定到任何任务计划程序),并且TryExecuteTask将失败并出现该错误。 描述相当神秘,因为任何实际TaskScheduler都与null不同。

对于您创建的任务而未运行,Task.RunSynchronouslyTask.Start的重载需要TaskScheduler

对于自动开始运行的任务,TaskFactory.StartNewTaskFactory<TResult>.StartNew的过载需要TaskScheduler

对于延续任务,有Task.ContinueWithTask<TResult>.ContinueWithTaskFactory.ContinueWhenAllTaskFactory.ContinueWhenAny的重载需要TaskScheduler

不采用任务计划程序的重载等效于指定TaskScheduler.Current。 对于TaskFactory,对于默认Task.Factory或在调用工厂方法时没有任务计划程序创建的也是如此,否则将使用工厂的任务计划程序。


与总是使用TaskScheduler.Default的新Task.Run的重载形成对比。 根据大多数有经验的人的说法,线程池调度程序更需要作为默认值,而不是TaskScheduler.Current线程绑定,但是更改现有API的协定为时已晚。

相关内容

  • 没有找到相关文章

最新更新