如何实现线程的暂停与resume?

spdcat 2015-01-28 04:05:14

class A : Window {
B b;
Thread thread;

A() {
b = new B();
thread = new Thread(b.doSomething);
}

void start() {
thread.Start();
}

void pause() {
//不要使用下面这个方法
//thread.Suspend();
}

void resume() {
//不要使用下面这个方法
//thread.Resume();
}
}


class B {
void doSomething() {
for(int i = 0; i!=10000; ++i) {
File file = ....
writeToFile(".....", file);
writeToFile(".....", file);
writeToFile(".....", file);
//......
writeToFile(".....", file);

file.save();
}
}
}


现有A、B两类,A类为GUI,B类为真正执行任务的类
现在我想在A类上放一个按钮,来控制任务的暂停和继续
由于B类的 doSomething() 函数中,每次循环都是写入一个文件,所以我想要“在每次写完一个文件后再暂停”,即:在file.save();后判断要不要继续循环
我觉得可以通过用一个bool isPaused变量和Thread.Sleep(500);来实现,但是感觉又丑又傻,所以就想请教一下,有没有通过Thread类来实现的方法?
...全文
266 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
失落的神庙 2015-02-06
  • 打赏
  • 举报
回复
学习了。
lincolnandlinda 2015-01-29
  • 打赏
  • 举报
回复
引用 8 楼 github_22161131 的回复:
这种暂停使用ManualResetEventSlim或者ManualResetEvent类,在save之后wait这个event,默认让event处于signaled状态,wait就不会阻塞继续运行,点击暂停按钮,把event设置nonsignaled状态,当save之后wait时,就会阻塞。 写了个console方式的例子,支持暂停、继续、取消:

var cts = new CancellationTokenSource(); // cts用来取消任务
var ev = new ManualResetEventSlim(true); // ev用来暂停/继续任务
var t = new Thread(() => {
    while (!cts.Token.IsCancellationRequested)
    {
        Console.Write("."); Thread.Sleep(100); // 模拟任务
        try
        {
            ev.Wait(cts.Token); // 等待ev,等待中可接受取消
        }
        catch(OperationCanceledException)
        {
            break;
        }
    }
});
t.Start();

while (true)
{
    if (Console.ReadKey(true).KeyChar == 'q')
    {
        // 按 q 键退出,退出前取消任务并等待工作线程彻底结束
        cts.Cancel();
        t.Join();
        return;
    }

    // 按其它键切换暂停/继续
    if (ev.IsSet)
        ev.Reset();
    else
        ev.Set();
}
正解.
种草德鲁伊 2015-01-29
  • 打赏
  • 举报
回复
且不看楼主的具体需求,用8F的方法是对的。
於黾 2015-01-29
  • 打赏
  • 举报
回复
虽然不占CPU,但是还占着内存(堆栈) 其实你不如把线程里使用的局部变量都定义成全局变量,这样即使线程退出了,所有变量也都还在,用不着自己想办法把大量变量自己保存. 或者你像楼上说的,用ManualResetEvent类
失落的神庙 2015-01-29
  • 打赏
  • 举报
回复
void ThreadRun()
{
while (!IsStop)
{
b.doSomething();
while(tempstop&&!IsStop){Thread.Sleep(50);}
}
}
thread = new Thread(new ThreadStart(ThreadRun));

失落的神庙 2015-01-29
  • 打赏
  • 举报
回复
while(tempstop&&!Stop){Thread.Sleep(50);} tempstop 暂停 Stop 停止
spdcat 2015-01-28
  • 打赏
  • 举报
回复
引用 3 楼 lovelj2012 的回复:
搞复杂了!对线程suspend、resume,完全木有必要啊! 在A类定义一个布尔变量
bool IsStop = false;
开启线程代码改成

void ThreadRun()
{
while (!IsStop)
{
b.doSomething();
}
}
thread = new Thread(new ThreadStart(ThreadRun));
当按钮点击暂停的时候,执行
IsStop = true;
我想做的是暂停,而不是停止,过一会之后可以从暂停的地方继续开始做 当执行了IsStop = true;之后,便跳出了那个while循环,故此方法不正确
spdcat 2015-01-28
  • 打赏
  • 举报
回复
引用 5 楼 Z65443344 的回复:
就如1楼所说 既然已经不想继续写了,那么就应该让线程退出 然后将结果保存,下一次继续的时候从这里开始,用另一个线程继续执行 而不是让当前线程等待
如果需要保存的东西很多呢 我也不是让当前线程“等待”,就是“暂停”一下,就在内存里放着,这总行吧,也不占CPU。这个做不到吗
spdcat 2015-01-28
  • 打赏
  • 举报
回复
引用 4 楼 Z65443344 的回复:
你觉得又丑又傻的方案恰恰是解决问题的唯一办法 除非你不要用while死循环,而采用面向对象的思想,引入事件的机制
我说“又丑又傻”的那个方法是,每sleep(500)就查看一次isPaused是否为true,这不是很傻么 而且我也没有限制说不让用事件的机制啊……愿闻其详
winnowc 2015-01-28
  • 打赏
  • 举报
回复
引用 6 楼 wanghui0380 的回复:
其实我一直想知道,为啥迅雷,BT这类玩意在传递文件的时候都有两个文件的原因。另外打开doc或access这类文件微软也会莫名其妙的多生成一个“不知所谓”的文件出来到底在干嘛
http://support.microsoft.com/kb/211632,简单说就是为了性能和数据安全。关于数据安全,或者说原子方式写文件,见http://blogs.msdn.com/b/adioltean/archive/2005/12/28/507866.aspx,最后有一个很长的步骤。VS保存文件的时候就是这样的,见http://bbs.csdn.net/topics/390964853。Word之类没测试过,不过我估计也是这样。
winnowc 2015-01-28
  • 打赏
  • 举报
回复
这种暂停使用ManualResetEventSlim或者ManualResetEvent类,在save之后wait这个event,默认让event处于signaled状态,wait就不会阻塞继续运行,点击暂停按钮,把event设置nonsignaled状态,当save之后wait时,就会阻塞。 写了个console方式的例子,支持暂停、继续、取消:

var cts = new CancellationTokenSource(); // cts用来取消任务
var ev = new ManualResetEventSlim(true); // ev用来暂停/继续任务
var t = new Thread(() => {
    while (!cts.Token.IsCancellationRequested)
    {
        Console.Write("."); Thread.Sleep(100); // 模拟任务
        try
        {
            ev.Wait(cts.Token); // 等待ev,等待中可接受取消
        }
        catch(OperationCanceledException)
        {
            break;
        }
    }
});
t.Start();

while (true)
{
    if (Console.ReadKey(true).KeyChar == 'q')
    {
        // 按 q 键退出,退出前取消任务并等待工作线程彻底结束
        cts.Cancel();
        t.Join();
        return;
    }

    // 按其它键切换暂停/继续
    if (ev.IsSet)
        ev.Reset();
    else
        ev.Set();
}
於黾 2015-01-28
  • 打赏
  • 举报
回复
迅雷具体不知道,但是你仔细看2个文件大小不一样,一个是真正的数据文件,另一个很小而且基本保持不变,估计是断点续传什么的用来保存一些信息的 而office生成一个临时文件,是用来保存你当前改动的,即使你没保存文件直接关机,下次打开的时候也会提示你可以恢复,而不是所有更改全部丢失
wanghui0380 2015-01-28
  • 打赏
  • 举报
回复
其实我一直想知道,为啥迅雷,BT这类玩意在传递文件的时候都有两个文件的原因。另外打开doc或access这类文件微软也会莫名其妙的多生成一个“不知所谓”的文件出来到底在干嘛
於黾 2015-01-28
  • 打赏
  • 举报
回复
就如1楼所说 既然已经不想继续写了,那么就应该让线程退出 然后将结果保存,下一次继续的时候从这里开始,用另一个线程继续执行 而不是让当前线程等待
於黾 2015-01-28
  • 打赏
  • 举报
回复
你觉得又丑又傻的方案恰恰是解决问题的唯一办法 除非你不要用while死循环,而采用面向对象的思想,引入事件的机制
江南小鱼 2015-01-28
  • 打赏
  • 举报
回复
搞复杂了!对线程suspend、resume,完全木有必要啊! 在A类定义一个布尔变量
bool IsStop = false;
开启线程代码改成

void ThreadRun()
{
while (!IsStop)
{
b.doSomething();
}
}
thread = new Thread(new ThreadStart(ThreadRun));
当按钮点击暂停的时候,执行
IsStop = true;
spdcat 2015-01-28
  • 打赏
  • 举报
回复
引用 1 楼 sp1234 的回复:
如果你不接着写文件,就应该结束线程了。然后等下次需要继续写的时候,再从上次剩余的那些数据开始(使用另一个线程)写。 线程本该结束了,你来个什么“暂停”,滥用线程干什么?
比如写到184个文件的时候,我在GUI上点击暂停,然后b把这第184个文件写完,暂停;下次就从第185个文件开始写
  • 打赏
  • 举报
回复
如果你不接着写文件,就应该结束线程了。然后等下次需要继续写的时候,再从上次剩余的那些数据开始(使用另一个线程)写。 线程本该结束了,你来个什么“暂停”,滥用线程干什么?

110,545

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧