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

时间:2017-01-23 11:03:13

标签: c# multithreading supersocket.net

我已经更新了一个使用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
            }));

出错了什么? 感谢

1 个答案:

答案 0 :(得分:0)

您必须启动任务才能将其绑定到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或者在调用工厂方法时没有任务调度程序创建的情况,这是正确的,否则工厂的任务使用调度程序。

与较新Task.Run的重载形成对比,后者始终使用TaskScheduler.Default。根据大多数经验丰富的人员的说法,线程池调度程序更常被视为默认值而不是可能受线程限制的TaskScheduler.Current,但更改现有API的合同为时已晚。