-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Description
I have a program that runs a thread which does BeginInvoke to update a label continuously with 20 ms sleeps. There's a button that resizes the form continuously (this.Size = new Size(..)) in a while loop with conditional that it only runs for 5 seconds. On .NET runtime on Windows and Mono runtime on Windows I'm able to run this same code and the application successfully completes the while-loop and becomes responsive to user input after 5 seconds (ish), which is not happening on Mono runtime on Linux. On Mono-Linux, it seems like there's unexpected behavior with resizing as compared to .NET runtime and Mono runtime on Windows machines. I'm finding this to be problematic most specifically when I have continuous background thread operations that use BeginInvoke to update the GUI.
Link to wine mono gitlab issue (duplicate) wine-mono#1. Let me know which issue I should delete, this one or that one.
Steps to Reproduce
- Create a new project and add this code to a .NET framework 4.5.2 project
- Run the program on a Linux machine
Code
using System;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using Timer = System.Windows.Forms.Timer;
namespace FormsApp2
{
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
public class Form1 : Form
{
CancellationTokenSource cancellationTokenSource;
private bool countActive = false;
System.Threading.Thread T;
private Color color1 = Color.Plum;
private Color color2 = Color.RoyalBlue;
Size minSize;
Size maxSize;
public Form1()
{
InitializeComponent();
this.DoubleBuffered = true;
this.SetStyle(ControlStyles.OptimizedDoubleBuffer |
ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint, true);
this.UpdateStyles();
button1.Click += Button1_Click;
button2.Click += Button2_Click;
Resize += Form1_Resize;
FormClosed += Form1_FormClosed;
minSize = new Size(this.Size.Width, this.Size.Height);
maxSize = new Size(this.Size.Width + 200, this.Size.Height + 200);
}
private void Button2_Click(object sender, EventArgs e)
{
Console.WriteLine(Environment.StackTrace);
try
{
var start = DateTime.UtcNow;
while ((DateTime.UtcNow - start).TotalMilliseconds < 5000)
{
Console.WriteLine("Resizing");
if ((DateTime.UtcNow - start).TotalMilliseconds < 2500 && this.Size.Width <= maxSize.Width)
{
this.Size = new Size(this.Width + 1, this.Height + 1);
}
else if (this.Size.Width >= minSize.Width)
{
this.Size = new Size(this.Width - 1, this.Height - 1);
}
}
}
catch(Exception ex)
{
closeEverything();
}
finally
{
Console.WriteLine(Environment.StackTrace);
Console.WriteLine("Button down press handler completed.");
}
}
private void Form1_Resize(object sender, EventArgs e)
{
Console.WriteLine("Entered Form1_Resize");
UpdateColorOfLabel();
}
private void Button1_Click(object sender, EventArgs e)
{
countActive = !countActive;
if (countActive)
{
cancellationTokenSource = new CancellationTokenSource();
T = new System.Threading.Thread(() => { Increment(cancellationTokenSource.Token); });
T.Start();
}
else
{
closeEverything();
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
closeEverything();
}
private void closeEverything()
{
if (T != null && cancellationTokenSource != null)
{
cancellationTokenSource.Cancel();
T.Join();
cancellationTokenSource.Dispose();
cancellationTokenSource = null;
}
}
private void UpdateColorOfLabel()
{
if (label2.BackColor == color1)
label2.BackColor = color2;
else
label2.BackColor = color1;
}
private void UpdateLabel(string Text)
{
if (InvokeRequired)
{
BeginInvoke(new Action(() => { UpdateLabel(Text); }));
return;
}
Console.WriteLine("Label is: " + Text);
label1.Text = Text;
}
private void Increment(CancellationToken token)
{
long i = 0;
try
{
while (true && countActive && !token.IsCancellationRequested)
{
Thread.Sleep(20);
i = (i + 1) % (long.MaxValue - 1);
UpdateLabel(i.ToString());
}
}
catch (Exception Ex)
{
}
}
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.button2 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(40, 45);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(145, 23);
this.button1.TabIndex = 0;
this.button1.Text = "Start/Stop Cntr";
this.button1.UseVisualStyleBackColor = true;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(290, 54);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(35, 13);
this.label1.TabIndex = 1;
this.label1.Text = "label1";
//
// label2
//
this.label2.AutoSize = true;
this.label2.BackColor = System.Drawing.Color.RoyalBlue;
this.label2.Location = new System.Drawing.Point(452, 54);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(19, 13);
this.label2.TabIndex = 2;
this.label2.Text = " ";
//
// button2
//
this.button2.Location = new System.Drawing.Point(40, 74);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(145, 23);
this.button2.TabIndex = 3;
this.button2.Text = "Resize";
this.button2.UseVisualStyleBackColor = true;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(538, 133);
this.Controls.Add(this.button2);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Button button2;
}
}
Current Behavior
Program becomes unresponsive after 5 seconds (Mono - Linux)
Expected Behavior
While loop should end after 5 seconds and program to become responsive again.
On which platforms did you notice this
[ ] macOS
[X] Linux
[ ] Windows
Version Used:
Mono JIT compiler version 6.12.0.200 (tarball Tue Jul 11 21:37:50 UTC 2023)
Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
TLS: __thread
SIGSEGV: altstack
Notifications: epoll
Architecture: amd64
Disabled: none
Misc: softdebug
Interpreter: yes
LLVM: yes(610)
Suspend: hybrid
GC: sgen (concurrent by default)
Stacktrace
Please paste the stack trace here if available.
This is the stack at the time of entering the while loop:
at System.Environment.get_StackTrace () [0x00000] in :0
at FormsApp2.Form1.Button2_Click (System.Object sender, System.EventArgs e) [0x00000] in <6ef6bc9fae37483ca2d55111084fbc1c>:0
at System.Windows.Forms.Control.OnClick (System.EventArgs e) [0x00000] in <25c2bdf9d79a43a599eb46bd15cd77fb>:0
at System.Windows.Forms.Button.OnClick (System.EventArgs e) [0x00000] in <25c2bdf9d79a43a599eb46bd15cd77fb>:0
at System.Windows.Forms.ButtonBase.OnMouseUp (System.Windows.Forms.MouseEventArgs mevent) [0x00000] in <25c2bdf9d79a43a599eb46bd15cd77fb>:0
at System.Windows.Forms.Button.OnMouseUp (System.Windows.Forms.MouseEventArgs mevent) [0x00000] in <25c2bdf9d79a43a599eb46bd15cd77fb>:0
at System.Windows.Forms.Control.WmLButtonUp (System.Windows.Forms.Message& m) [0x00000] in <25c2bdf9d79a43a599eb46bd15cd77fb>:0
at System.Windows.Forms.Control.WndProc (System.Windows.Forms.Message& m) [0x00000] in <25c2bdf9d79a43a599eb46bd15cd77fb>:0
at System.Windows.Forms.ButtonBase.WndProc (System.Windows.Forms.Message& m) [0x00000] in <25c2bdf9d79a43a599eb46bd15cd77fb>:0
at System.Windows.Forms.Button.WndProc (System.Windows.Forms.Message& m) [0x00000] in <25c2bdf9d79a43a599eb46bd15cd77fb>:0
at System.Windows.Forms.Control+ControlWindowTarget.OnMessage (System.Windows.Forms.Message& m) [0x00000] in <25c2bdf9d79a43a599eb46bd15cd77fb>:0
at System.Windows.Forms.Control+ControlNativeWindow.WndProc (System.Windows.Forms.Message& m) [0x00000] in <25c2bdf9d79a43a599eb46bd15cd77fb>:0
at System.Windows.Forms.NativeWindow.WndProc (System.IntPtr hWnd, System.Windows.Forms.Msg msg, System.IntPtr wParam, System.IntPtr lParam) [0x00000] in <25c2bdf9d79a43a599eb46bd15cd77fb>:0
at System.Windows.Forms.XplatUIX11.DispatchMessage (System.Windows.Forms.MSG& msg) [0x00000] in <25c2bdf9d79a43a599eb46bd15cd77fb>:0
at System.Windows.Forms.XplatUI.DispatchMessage (System.Windows.Forms.MSG& msg) [0x00000] in <25c2bdf9d79a43a599eb46bd15cd77fb>:0
at System.Windows.Forms.Application.RunLoop (System.Boolean Modal, System.Windows.Forms.ApplicationContext context) [0x00000] in <25c2bdf9d79a43a599eb46bd15cd77fb>:0
at System.Windows.Forms.Application.Run (System.Windows.Forms.ApplicationContext context) [0x00000] in <25c2bdf9d79a43a599eb46bd15cd77fb>:0
at System.Windows.Forms.Application.Run (System.Windows.Forms.Form mainForm) [0x00000] in <25c2bdf9d79a43a599eb46bd15cd77fb>:0
at FormsApp2.Program.Main () [0x00000] in <6ef6bc9fae37483ca2d55111084fbc1c>:0