如何改进Thread的这个包装?

dma*_*rra 0 c# multithreading

考虑以下抽象类:

public abstract class Worker {
    protected bool shutdown;
    protected Thread t;

    /// <summary>
    /// defines that we have an auto unpause scheduled
    /// </summary>
    private bool _unpauseScheduled;

    /// <summary>
    /// when paused; schedule an automatic unpause when we
    /// reach this datetime
    /// </summary>
    private DateTime pauseUntil;


    private bool _isStopped = true;
    public bool IsStopped {
        get {
            return t.ThreadState == ThreadState.Stopped;
        }
    }

    private bool _isPaused = false;
    public bool IsPaused {
        get {
            return _isPaused;
        }
    }

    private string stringRepresentation;

    public Worker() {  
        t = new Thread(ThreadFunction);
        stringRepresentation = "Thread id:" + t.ManagedThreadId;
        t.Name = stringRepresentation;
    }

    public Worker(string name) {   
        t = new Thread(ThreadFunction);
        stringRepresentation = name;
        t.Name = stringRepresentation;
    }


    public void Start() {
        OnBeforeThreadStart();
        t.Start();
    }

    public void ScheduleStop() {
        shutdown = true;
    }

    public void SchedulePause() {
        OnPauseRequest();
        _isPaused = true;
    }

    public void SchedulePause(int seconds) {
        _unpauseScheduled = true;
        pauseUntil = DateTime.Now.AddSeconds(seconds);
        SchedulePause();
    }

    public void Unpause() {
        _isPaused = false;
        _unpauseScheduled = false;            
    }

    public void ForceStop() {
        t.Abort();
    }


    /// <summary>
    /// The main thread loop.
    /// </summary>
    private void ThreadFunction() {
        OnThreadStart();
        while (!shutdown) {
            OnBeforeLoop();
            if (!IsPaused) {
                if (!OnLoop()) {
                    break;
                }
            } else {
                // check for auto-unpause;
                if (_unpauseScheduled && pauseUntil < DateTime.Now) {
                    Unpause();
                }
            }
            OnAfterLoop();
            Thread.Sleep(1000);
        }
        OnShutdown();           
    }


    public abstract void OnBeforeThreadStart();
    public abstract void OnThreadStart();
    public abstract void OnBeforeLoop();
    public abstract bool OnLoop();
    public abstract void OnAfterLoop();
    public abstract void OnShutdown();
    public abstract void OnPauseRequest();


    public override string ToString() {
        return stringRepresentation;
    }
}  
Run Code Online (Sandbox Code Playgroud)

我使用此类创建旨在运行应用程序生命周期的Threads,同时还可以根据需要暂停和停止线程.

我忍不住摇摇晃晃地感觉我的实施是天真的.我使用Thread.Sleep()让我停下来.我仍然在学习线程的细节,我希望看到其他人可能做的事情.

Worker派生对象需要能够执行以下操作:

  1. 运行应用程序的生命周期(或只要需要)
  2. 能够安全地停止(完成在OnLoop()中正在做的事情)
  3. 能够不安全地停止(忽略OnLoop()中发生的事情)
  4. 能够暂停执行一段时间(或无限期)

现在,我的实施工作,但这对我来说不够好.我想使用良好的练习,我可以使用一些评论来帮助我.

Eri*_*ert 5

我忍不住摇摇晃晃地感觉我的实施是天真的.我使用Thread.Sleep()让我停下来.我仍然在学习线程的细节,我希望看到其他人可能做的事情.

你的直觉在这里很好; 这是一种天真的方法,每当你在生产代码中使用一个线程时,你应该认真思考是否犯了错误.你要为那个工人付钱; 你为什么付钱睡觉?

将线程置于睡眠状态直到需要的正确方法是不要在循环中进行休眠和轮询.改为使用适当的等待句柄; 这就是等待句柄的用途.

但更好的方法仍然是将空闲线程放回线程池中; 如果将来需要再次启动工作,请将其安排到新的工作线程中.一个可以永远睡觉的线程是一种巨大的资源浪费; 记住,默认情况下,一个线程是一百万字节的内存.你会分配一堆百万字节的数组然后从不使用它们吗?

您应该学习任务并行库的设计以获得更多灵感.TPL的洞察力是线程是工作者,但你关心的是完成任务.你的方法在线程之上放置了一个薄层,但它没有超越线程是工作者的事实; 管理工人是一种痛苦.陈述您的任务,让TPL将它们分配给工人.

您还可以检查围绕各种标志的最新情况的假设.它们没有锁定且不易变,因此读取和写入可以基本上在CPU的奇思妙想中及时向前和向后移动.

您还需要考虑一些非线程错误.例如,假设您决定暂停30分钟,但在时钟"前进"前五分钟进行夏令时.你停了半个小时,还是五分钟?你真的打算做什么?