繁体   English   中英

Thread.Sleep永不返回

[英]Thread.Sleep never returns

我有一个可以在表单上绘制东西的应用程序(只是一个测试应用程序)。 我遇到Thread.Sleep的问题。 我使用每100毫秒启动DrawinArea重绘的线程。 它工作正常,但有时此线程无法从This.Sleep(100)调用返回。 我已经检查了调试器,并且确定问题出在Thread.Sleep()中。

注意:它需要Gtk#才能运行。

using System;
using Gtk;
using Cairo;
using System.Threading;
using System.Timers;

public partial class MainWindow: Gtk.Window
{

    Thread redrawThread = new Thread(Redrawer);

    //System.Timers.Timer timer = new System.Timers.Timer();

    static int calls = 0;

    public MainWindow()
        : base(Gtk.WindowType.Toplevel)
    {
        Build();
        this.drawingarea2.ExposeEvent += OnExpose;

        redrawThread.Name = "Redraw Thread";

        redrawThread.Start(this);
        /*
        timer.Interval = 100;
        timer.Elapsed += (sender, e) =>
        {
            drawingarea2.QueueDraw();
        };
        timer.AutoReset = true;
        timer.Start();*/

    }

    protected void OnDeleteEvent(object sender, DeleteEventArgs a)
    {
        redrawThread.Abort();
        Application.Quit();
        a.RetVal = true;
    }


    static void Redrawer(object wnd) {
        var area = (MainWindow)wnd;
        while (true)
        {
            Thread.Sleep(100);
            area.QueueDraw();
        }
    }

    int x = 200;
    int x_mod = 10;
    int y = 150;
    int y_mod = 10;



    void OnExpose(object sender, ExposeEventArgs args) {

        var area = (DrawingArea)sender;

        if (x + 10 >= drawingarea2.Allocation.Width || x - 10 < 0)
            x_mod = -x_mod;

        if (y + 10 >= drawingarea2.Allocation.Height || y - 10 < 0)
            y_mod = -y_mod;

        x += x_mod;
        y += y_mod;

        var ny = Math.Abs(y - drawingarea2.Allocation.Height);

        using (var ctx = Gdk.CairoHelper.Create(area.GdkWindow))
        {


            ctx.LineWidth = 9;
            ctx.SetSourceRGB(0.7, 0.2, 0.0);

            ctx.Arc(x, ny, 10, 0, 2*Math.PI);
            ctx.StrokePreserve();

            ctx.SetSourceRGB(0.3, 0.4, 0.6);
            ctx.Fill();

            ctx.GetTarget().Dispose();
        }


    }

}

遇到此问题后,我决定切换到System.Timers.Timer,但是我也遇到了问题。 计时器会在一段时间后停止触发事件。 我搜索了此问题,发现如果没有任何引用,GC可以销毁计时器。 我的计时器是类成员,因此引用始终存在,但无论如何,它都会停止。 问题是什么?

QueueDraw()的文档中可以QueueDraw()

等效于为小部件的整个区域调用Widget.QueueDrawArea。

阅读状态为QueueDrawArea的文档

使小部件的矩形区域无效[...]。 一旦主循环变为空闲状态(大致处理完当前一批事件之后),该窗口将收到Widget.ExposeEvent事件,用于所有无效区域的并集。

发生的情况是,每100毫秒您将另一条消息放入主窗口的队列中,而主窗口花费的时间超过100毫秒来处理此请求。 因为您生成重绘请求的速度快于它无法满足重绘请求的速度,所以这将泛滥队列,并且一旦达到最大大小,就无法接收到新消息,它会“锁定”。

当您说过通过更新窗口标题来测试时,还需要继续进行更新才能完成更新,但是由于队列已满,所以标题更改从未显示出来。 睡眠没有挂起,只是您的调试方法由于相同的潜在问题而中断。

解决方案是较少调用QueueDraw()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM