Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使后台线程睡眠与调用一起工作_C#_Multithreading_Sleep_Invoke - Fatal编程技术网

C# 如何使后台线程睡眠与调用一起工作

C# 如何使后台线程睡眠与调用一起工作,c#,multithreading,sleep,invoke,C#,Multithreading,Sleep,Invoke,我在表单上有一个PictureBox控件,应该每100毫秒绘制一次 后台线程在循环中执行一些计算,在每次迭代之后,它都会触发一个事件 编辑(作为对评论的回复): 调用包装器(因为要绘制到的控件是在UI线程中创建的) 现在,我希望for循环在每次迭代后暂停100毫秒,所以我添加了Thread.Sleep(100);在触发事件之前: for (int i = 0; i < stepsCount; i++) { IPiece piece = Calculate(); if (O

我在表单上有一个PictureBox控件,应该每100毫秒绘制一次

后台线程在循环中执行一些计算,在每次迭代之后,它都会触发一个事件

编辑(作为对评论的回复):

调用包装器(因为要绘制到的控件是在UI线程中创建的)

现在,我希望for循环在每次迭代后暂停100毫秒,所以我添加了Thread.Sleep(100);在触发事件之前:

for (int i = 0; i < stepsCount; i++) {
    IPiece piece = Calculate();
    if (OnPieceStep != null) {
        Thread.Sleep(100);
        OnPieceStep(piece);
    }
}
for(int i=0;i
但是,这不会每100毫秒刷新pictureBox,而是仅绘制循环的最后一次迭代,并且仅在循环完成后绘制


不应该线程。睡眠暂停它被调用的线程,而不是UI线程?
更新:我刚刚尝试在后台线程计算时单击应用程序。程序阻塞(“无响应”),因此Thread.Sleep显然是在UI线程上调用的。这是预期的行为还是我的线程有问题?

从线程角度看,一切看起来都很好。 最有可能的问题依赖于内置drawScreen(IPiece-piece)方法。绘图后是否尝试刷新/更新窗口

一些见解: Control.Invoke方法使用Win32 SendMessage函数将作为参数提供的委托作为窗口消息传递。

如上所述:

睡眠是世界上独一无二的 挂起的阻塞方法 Windows消息在 Windows窗体应用程序或COM 线程上的环境 单线程公寓模型是 用过。这无关紧要 对于Windows窗体应用程序,在 任何长时间的阻塞操作 主UI线程将使 应用程序无响应–并且是 因此,通常避免——不管怎样 消息是否被泵送 “技术上”被暂停。这个 遗留问题的情况更为复杂 COM托管环境,它可以 有时,我们希望边睡觉边休息 保持消息的活跃性。 微软的Chris Brumme讨论 这在他的网络日志中详细列出(搜索: “COM”克里斯·布鲁姆“)


WinForms中的Thread.Sleep()似乎总是暂停UI,无论在哪个线程中调用。

不应该执行线程。Sleep是否暂停调用的线程?(请注意,所描述的for循环在UI线程上不起作用。)我不能为此使用计时器,因为它不是计时事件,而是取决于计算。我唯一想要的是,在计算完成后,工作线程暂停100毫秒,然后触发一个事件。计算的持续时间甚至可以是一分钟,因此我不能使用每100毫秒触发一次的计时器。我可以使用计时器的唯一方法是将触发事件的时间推迟100毫秒,但我认为有一种代码清理的方法。_drawScreen()只创建一个空白位图,获取一个Graphics.FromImage,绘制一些圆,然后将pictureBox.Image设置为位图。这一切都是在UI线程中完成的(因为调用),所以我不明白为什么每次迭代后都不应该绘制,而是在整个循环完成后才绘制。绘制后是否使picturebox无效?不是很明确,但是我只是尝试了显式地失效,结果是一样的。我编辑了代码以反映调用结构。
public class World { 

    void BackgroundWorkerFunction() {
        IPiece piece = PieceFactory.Create();
        for (int i = 0; i < stepsCount; i++) {
            piece.Calculate();
            if (OnPieceStep != null) {
                OnPieceStep(piece);
            }
        }
    }

}
world.OnPieceStep += DrawScreen;
void DrawScreen(IPiece piece) {
    this.Invoke(new PieceStep(_drawScreen), piece);
}
void _drawScreen(IPiece piece) {
    drawer.Draw(world.Board, piece);
}
for (int i = 0; i < stepsCount; i++) {
    IPiece piece = Calculate();
    if (OnPieceStep != null) {
        Thread.Sleep(100);
        OnPieceStep(piece);
    }
}