Gui.cs: MainLoop.RunTimers(): System.ArgumentException: 'An entry with the same key already exists

Created on 31 Jul 2020  路  11Comments  路  Source: migueldeicaza/gui.cs

Hello,

I'm having trouble in the MainLoop execution which is throwing an exception in the RunTimers() method. It is failing when trying to add the Timeout back to be run again in the next iteration. The issue seems to be that the calculated ticks can be a duplicate with what is already in the SortedList which then throws the exception. I'm thinking that when RunTimers() adds the Timeouts back for the next iteration, it causes DateTime.UtcNow to possibly be the same for multiple timeouts. So then any timeouts with the same TimeSpan defined would then cause a collision.

image
image

bug

All 11 comments

One possible solution might be to implement a custom IComparer that allows for duplicate keys.

It is failing when trying to add the Timeout back to be run again in the next iteration.

Can you show how you are doing this please.

Ill see if I can come up with a simple recreation.

This code triggers the exception before the MainLoop can even run.

```c#
public static void Main()
{
Application.Init();

var window = new Window() { Height = Dim.Fill(), Width = Dim.Fill() };
Application.Top.Add(window);

var progress1 = new ProgressBar() { Height = 1, Width = Dim.Fill(), Y = 1 };
var progress2 = new ProgressBar() { Height = 1, Width = Dim.Fill(), Y = 2 };

window.Add(progress1);
window.Add(progress2);

Application.MainLoop.AddTimeout(TimeSpan.FromMilliseconds(100), loop =>
{
    progress1.Pulse();
    return true;
});

Application.MainLoop.AddTimeout(TimeSpan.FromMilliseconds(100), loop =>
{
    progress2.Pulse();
    return true;
});

Application.Run();

}
```

This code snippet will make it through and execute Application.Run(), but when the MainLoop attempts to setup the next iteration of the Timeouts, thats when it will throw the exception.

```c#
public static void Main()
{
Application.Init();

var window = new Window() { Height = Dim.Fill(), Width = Dim.Fill() };
Application.Top.Add(window);

var progress1 = new ProgressBar() { Height = 1, Width = Dim.Fill(), Y = 1 };
var progress2 = new ProgressBar() { Height = 1, Width = Dim.Fill(), Y = 2 };
var progress3 = new ProgressBar() { Height = 1, Width = Dim.Fill(), Y = 3 };

window.Add(progress1);
window.Add(progress2);
window.Add(progress3);

Application.MainLoop.AddTimeout(TimeSpan.FromMilliseconds(100), loop =>
{
    progress1.Pulse();
    return true;
});

Thread.Sleep(1000);
Application.MainLoop.AddTimeout(TimeSpan.FromMilliseconds(100), loop =>
{
    progress2.Pulse();
    return true;
});

Thread.Sleep(1000);
Application.MainLoop.AddTimeout(TimeSpan.FromMilliseconds(100), loop =>
{
    progress3.Pulse();
    return true;
});

Application.Run();

}
```

None of them are giving any error. Do you are using the nuget package or the Gui repository?

I am running a clone of master.

I haven't any exception.

run-timers

This might be something you are doing that there isn't in these snippets that is causing the exception.

I鈥檒l pull from master again and rerun my test but I鈥檒l post the whole Program class along with my .csproj when I have a chance.

Does this still repro? I'm closing for now. Please comment if it's still repro and we can reopen.

Was this page helpful?
0 / 5 - 0 ratings