我已经更新了一个使用Supersocket连接旧c ++服务器的旧项目。使用最新版本(从0.7.0 => 0.8.0.8)我在尝试重新连接时遇到异常(它说套接字是在另一个线程上打开的)我希望有一个排队任务的类(第一个连接)并重新连接)并在一个专门的线程上运行它们。
我看过this方法,但当我尝试运行创建的任务时遇到异常
ExecuteTask may not be called for a task which was previously queued to a different TaskScheduler.
这是我从上面的链接中获取的课程
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
}));
出错了什么? 感谢
答案 0 :(得分:0)
您必须启动任务才能将其绑定到TaskScheduler
。在您的代码中,您需要手动对任务进行排队,反之亦然,因此任务不会绑定到您的任务调度程序(或任何根本),TryExecuteTask
将失败有这个错误。描述相当神秘,因为任何实际的TaskScheduler
都与null
不同。
对于您未创建的任务,Task.RunSynchronously
和Task.Start
的重载需要TaskScheduler
。
对于自动开始运行的任务,TaskFactory.StartNew
和TaskFactory<TResult>.StartNew
的重载需要TaskScheduler
。
对于延续任务,有Task.ContinueWith
,Task<TResult>.ContinueWith
,TaskFactory.ContinueWhenAll
和TaskFactory.ContinueWhenAny
的重载需要TaskScheduler
。
不执行任务调度程序的重载等同于指定TaskScheduler.Current
。在TaskFactory
的情况下,对于默认的Task.Factory
或者在调用工厂方法时没有任务调度程序创建的情况,这是正确的,否则工厂的任务使用调度程序。
与较新Task.Run
的重载形成对比,后者始终使用TaskScheduler.Default
。根据大多数经验丰富的人员的说法,线程池调度程序更常被视为默认值而不是可能受线程限制的TaskScheduler.Current
,但更改现有API的合同为时已晚。