How to avoid deadlock with Observable FromEventPattern Async routines?





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







0















I am using Observable / reactive extensions to debounce certain events, like button clicks or entering text into a textbox. However, in the event of a shutdown or close, I need to await any pending events so that save operations can complete, etc.



The following code will deadlock.



Button b1 = new Button();

var scheduler = new EventLoopScheduler(ts => new Thread(ts)
{
IsBackground = false
});

var awaiter = Observable.FromEventPattern(h => b1.Click += h, h => b1.Click -= h, scheduler)
.Throttle(TimeSpan.FromMilliseconds(5000), scheduler)
.FirstOrDefaultAsync();

someTaskList.add(awaiter.ToTask());

awaiter.Subscribe
(
x =>
{
//do some work in response to click event
}
);

//program continues...


Then, elsewhere in the application



private async Task CloseApplicationSafely()
{
await AwaitPendingEvents();
}

private async Task AwaitPendingEvents()
{
if(someTaskList.Count > 0)
{
await Task.WhenAll(someTaskList);
}
}


The program will then deadlock, awaiting forever if a button click has never occurred. Here is another example, but with a textbox.



var completedTask = Observable.FromEventPattern(h => t1.TextChanged += h, h => t1.TextChanged -= h, scheduler)
.Select(x => ((TextBox)x.Sender).Text)
.DistinctUntilChanged()
.Throttle(TimeSpan.FromMilliseconds(5000), scheduler)
.ForEachAsync(txt =>
{
//do some work, save the text
});

someTaskList.Add(completedTask);


In this case it doesn't matter if text was ever changed or not. The variable completedTask will deadlock forever if you await it. ForEachAsync() returns a task, which seems to never be activated.



What am I doing wrong? Hopefully my intended function is clear. I am debouncing events. But I need to await any pending events that are in the process of being debounced to ensure they complete. And if there are no pending events, continue without waiting. Thanks.










share|improve this question























  • Can you clarify what a pending event is? Where is the source of pending events?

    – Shlomo
    Jan 3 at 20:45











  • I'm not sure I understand your question. See source. Observable binds to control events like Click or TextChanged. Those events are then debounced with Throttle(). So you could rapid fire click the button many times, but it will then wait until 5 seconds after you're last click before firing a single event through the subscription. This is what I refer to as pending events. A human has clicked, but the subscription has not been executed yet.

    – Andrew
    Jan 3 at 20:51






  • 1





    This isn't a deadlock. A deadlock is a circular dependency. A is waiting on B, B is waiting on A, so they can never finish because neither will let the other finish. You're just waiting on something that will never finish, but that thing that will never finish isn't dependent on anything else, it's just something that won't ever finish. This is an important distinction because they're resolved differently. For a deadlock you remove the circular dependency, for a task that never completes, you either need to force it to complete anyway, or check whether or not it will complete before waiting.

    – Servy
    Jan 3 at 21:04











  • You need to have the observable end when you want the program to end. Try using .Take or .TakeUntil to do it.

    – Enigmativity
    Jan 3 at 22:47


















0















I am using Observable / reactive extensions to debounce certain events, like button clicks or entering text into a textbox. However, in the event of a shutdown or close, I need to await any pending events so that save operations can complete, etc.



The following code will deadlock.



Button b1 = new Button();

var scheduler = new EventLoopScheduler(ts => new Thread(ts)
{
IsBackground = false
});

var awaiter = Observable.FromEventPattern(h => b1.Click += h, h => b1.Click -= h, scheduler)
.Throttle(TimeSpan.FromMilliseconds(5000), scheduler)
.FirstOrDefaultAsync();

someTaskList.add(awaiter.ToTask());

awaiter.Subscribe
(
x =>
{
//do some work in response to click event
}
);

//program continues...


Then, elsewhere in the application



private async Task CloseApplicationSafely()
{
await AwaitPendingEvents();
}

private async Task AwaitPendingEvents()
{
if(someTaskList.Count > 0)
{
await Task.WhenAll(someTaskList);
}
}


The program will then deadlock, awaiting forever if a button click has never occurred. Here is another example, but with a textbox.



var completedTask = Observable.FromEventPattern(h => t1.TextChanged += h, h => t1.TextChanged -= h, scheduler)
.Select(x => ((TextBox)x.Sender).Text)
.DistinctUntilChanged()
.Throttle(TimeSpan.FromMilliseconds(5000), scheduler)
.ForEachAsync(txt =>
{
//do some work, save the text
});

someTaskList.Add(completedTask);


In this case it doesn't matter if text was ever changed or not. The variable completedTask will deadlock forever if you await it. ForEachAsync() returns a task, which seems to never be activated.



What am I doing wrong? Hopefully my intended function is clear. I am debouncing events. But I need to await any pending events that are in the process of being debounced to ensure they complete. And if there are no pending events, continue without waiting. Thanks.










share|improve this question























  • Can you clarify what a pending event is? Where is the source of pending events?

    – Shlomo
    Jan 3 at 20:45











  • I'm not sure I understand your question. See source. Observable binds to control events like Click or TextChanged. Those events are then debounced with Throttle(). So you could rapid fire click the button many times, but it will then wait until 5 seconds after you're last click before firing a single event through the subscription. This is what I refer to as pending events. A human has clicked, but the subscription has not been executed yet.

    – Andrew
    Jan 3 at 20:51






  • 1





    This isn't a deadlock. A deadlock is a circular dependency. A is waiting on B, B is waiting on A, so they can never finish because neither will let the other finish. You're just waiting on something that will never finish, but that thing that will never finish isn't dependent on anything else, it's just something that won't ever finish. This is an important distinction because they're resolved differently. For a deadlock you remove the circular dependency, for a task that never completes, you either need to force it to complete anyway, or check whether or not it will complete before waiting.

    – Servy
    Jan 3 at 21:04











  • You need to have the observable end when you want the program to end. Try using .Take or .TakeUntil to do it.

    – Enigmativity
    Jan 3 at 22:47














0












0








0








I am using Observable / reactive extensions to debounce certain events, like button clicks or entering text into a textbox. However, in the event of a shutdown or close, I need to await any pending events so that save operations can complete, etc.



The following code will deadlock.



Button b1 = new Button();

var scheduler = new EventLoopScheduler(ts => new Thread(ts)
{
IsBackground = false
});

var awaiter = Observable.FromEventPattern(h => b1.Click += h, h => b1.Click -= h, scheduler)
.Throttle(TimeSpan.FromMilliseconds(5000), scheduler)
.FirstOrDefaultAsync();

someTaskList.add(awaiter.ToTask());

awaiter.Subscribe
(
x =>
{
//do some work in response to click event
}
);

//program continues...


Then, elsewhere in the application



private async Task CloseApplicationSafely()
{
await AwaitPendingEvents();
}

private async Task AwaitPendingEvents()
{
if(someTaskList.Count > 0)
{
await Task.WhenAll(someTaskList);
}
}


The program will then deadlock, awaiting forever if a button click has never occurred. Here is another example, but with a textbox.



var completedTask = Observable.FromEventPattern(h => t1.TextChanged += h, h => t1.TextChanged -= h, scheduler)
.Select(x => ((TextBox)x.Sender).Text)
.DistinctUntilChanged()
.Throttle(TimeSpan.FromMilliseconds(5000), scheduler)
.ForEachAsync(txt =>
{
//do some work, save the text
});

someTaskList.Add(completedTask);


In this case it doesn't matter if text was ever changed or not. The variable completedTask will deadlock forever if you await it. ForEachAsync() returns a task, which seems to never be activated.



What am I doing wrong? Hopefully my intended function is clear. I am debouncing events. But I need to await any pending events that are in the process of being debounced to ensure they complete. And if there are no pending events, continue without waiting. Thanks.










share|improve this question














I am using Observable / reactive extensions to debounce certain events, like button clicks or entering text into a textbox. However, in the event of a shutdown or close, I need to await any pending events so that save operations can complete, etc.



The following code will deadlock.



Button b1 = new Button();

var scheduler = new EventLoopScheduler(ts => new Thread(ts)
{
IsBackground = false
});

var awaiter = Observable.FromEventPattern(h => b1.Click += h, h => b1.Click -= h, scheduler)
.Throttle(TimeSpan.FromMilliseconds(5000), scheduler)
.FirstOrDefaultAsync();

someTaskList.add(awaiter.ToTask());

awaiter.Subscribe
(
x =>
{
//do some work in response to click event
}
);

//program continues...


Then, elsewhere in the application



private async Task CloseApplicationSafely()
{
await AwaitPendingEvents();
}

private async Task AwaitPendingEvents()
{
if(someTaskList.Count > 0)
{
await Task.WhenAll(someTaskList);
}
}


The program will then deadlock, awaiting forever if a button click has never occurred. Here is another example, but with a textbox.



var completedTask = Observable.FromEventPattern(h => t1.TextChanged += h, h => t1.TextChanged -= h, scheduler)
.Select(x => ((TextBox)x.Sender).Text)
.DistinctUntilChanged()
.Throttle(TimeSpan.FromMilliseconds(5000), scheduler)
.ForEachAsync(txt =>
{
//do some work, save the text
});

someTaskList.Add(completedTask);


In this case it doesn't matter if text was ever changed or not. The variable completedTask will deadlock forever if you await it. ForEachAsync() returns a task, which seems to never be activated.



What am I doing wrong? Hopefully my intended function is clear. I am debouncing events. But I need to await any pending events that are in the process of being debounced to ensure they complete. And if there are no pending events, continue without waiting. Thanks.







c# observable system.reactive






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Jan 3 at 20:27









AndrewAndrew

13




13













  • Can you clarify what a pending event is? Where is the source of pending events?

    – Shlomo
    Jan 3 at 20:45











  • I'm not sure I understand your question. See source. Observable binds to control events like Click or TextChanged. Those events are then debounced with Throttle(). So you could rapid fire click the button many times, but it will then wait until 5 seconds after you're last click before firing a single event through the subscription. This is what I refer to as pending events. A human has clicked, but the subscription has not been executed yet.

    – Andrew
    Jan 3 at 20:51






  • 1





    This isn't a deadlock. A deadlock is a circular dependency. A is waiting on B, B is waiting on A, so they can never finish because neither will let the other finish. You're just waiting on something that will never finish, but that thing that will never finish isn't dependent on anything else, it's just something that won't ever finish. This is an important distinction because they're resolved differently. For a deadlock you remove the circular dependency, for a task that never completes, you either need to force it to complete anyway, or check whether or not it will complete before waiting.

    – Servy
    Jan 3 at 21:04











  • You need to have the observable end when you want the program to end. Try using .Take or .TakeUntil to do it.

    – Enigmativity
    Jan 3 at 22:47



















  • Can you clarify what a pending event is? Where is the source of pending events?

    – Shlomo
    Jan 3 at 20:45











  • I'm not sure I understand your question. See source. Observable binds to control events like Click or TextChanged. Those events are then debounced with Throttle(). So you could rapid fire click the button many times, but it will then wait until 5 seconds after you're last click before firing a single event through the subscription. This is what I refer to as pending events. A human has clicked, but the subscription has not been executed yet.

    – Andrew
    Jan 3 at 20:51






  • 1





    This isn't a deadlock. A deadlock is a circular dependency. A is waiting on B, B is waiting on A, so they can never finish because neither will let the other finish. You're just waiting on something that will never finish, but that thing that will never finish isn't dependent on anything else, it's just something that won't ever finish. This is an important distinction because they're resolved differently. For a deadlock you remove the circular dependency, for a task that never completes, you either need to force it to complete anyway, or check whether or not it will complete before waiting.

    – Servy
    Jan 3 at 21:04











  • You need to have the observable end when you want the program to end. Try using .Take or .TakeUntil to do it.

    – Enigmativity
    Jan 3 at 22:47

















Can you clarify what a pending event is? Where is the source of pending events?

– Shlomo
Jan 3 at 20:45





Can you clarify what a pending event is? Where is the source of pending events?

– Shlomo
Jan 3 at 20:45













I'm not sure I understand your question. See source. Observable binds to control events like Click or TextChanged. Those events are then debounced with Throttle(). So you could rapid fire click the button many times, but it will then wait until 5 seconds after you're last click before firing a single event through the subscription. This is what I refer to as pending events. A human has clicked, but the subscription has not been executed yet.

– Andrew
Jan 3 at 20:51





I'm not sure I understand your question. See source. Observable binds to control events like Click or TextChanged. Those events are then debounced with Throttle(). So you could rapid fire click the button many times, but it will then wait until 5 seconds after you're last click before firing a single event through the subscription. This is what I refer to as pending events. A human has clicked, but the subscription has not been executed yet.

– Andrew
Jan 3 at 20:51




1




1





This isn't a deadlock. A deadlock is a circular dependency. A is waiting on B, B is waiting on A, so they can never finish because neither will let the other finish. You're just waiting on something that will never finish, but that thing that will never finish isn't dependent on anything else, it's just something that won't ever finish. This is an important distinction because they're resolved differently. For a deadlock you remove the circular dependency, for a task that never completes, you either need to force it to complete anyway, or check whether or not it will complete before waiting.

– Servy
Jan 3 at 21:04





This isn't a deadlock. A deadlock is a circular dependency. A is waiting on B, B is waiting on A, so they can never finish because neither will let the other finish. You're just waiting on something that will never finish, but that thing that will never finish isn't dependent on anything else, it's just something that won't ever finish. This is an important distinction because they're resolved differently. For a deadlock you remove the circular dependency, for a task that never completes, you either need to force it to complete anyway, or check whether or not it will complete before waiting.

– Servy
Jan 3 at 21:04













You need to have the observable end when you want the program to end. Try using .Take or .TakeUntil to do it.

– Enigmativity
Jan 3 at 22:47





You need to have the observable end when you want the program to end. Try using .Take or .TakeUntil to do it.

– Enigmativity
Jan 3 at 22:47












1 Answer
1






active

oldest

votes


















0














Comments from both @Servy and @Enigmativity helped me pin it down. For those interested, here is the solution I came up with. Any suggestions on my approach let me know.



I created a static helper class named WaitableEventHelper, which includes the following function.



public static Task WaitableDebouncer(
this Control c,
Action<EventHandler> addHandler,
Action<EventHandler> removeHandler,
IScheduler scheduler,
CancellationToken cancelToken,
TimeSpan limit,
Func<Task> func)
{
var mycts = new CancellationTokenSource();

bool activated = false;
bool active = false;

Func<Task> pending = null;

var awaiter = Observable.FromEventPattern(addHandler, removeHandler, scheduler)
.TakeUntil(x => { return cancelToken.IsCancellationRequested; })
.Do((x) => { activated = true; })
.Do((x) =>
{
//sets pending task to last in sequence
pending = func;
})
.Throttle(limit, scheduler)
.Do((x) => { active = true; }) //done with throttle
.ForEachAsync(async (x) =>
{
//get func
var f = pending;

//remove from list
pending = null;

//execute it
await f();

//have we been cancelled?
if (cancelToken.IsCancellationRequested)
{
mycts.Cancel();
}

//not active
active = false;

}, mycts.Token);

//if cancelled
cancelToken.Register(() =>
{
//never activated, force cancel
if (!activated)
{
mycts.Cancel();
}

//activated in the past but not currently active
if (activated && !active)
{
mycts.Cancel();
}
});

//return new awaiter based on conditions
return Task.Run(async () =>
{
try
{
//until awaiter finishes or is cancelled, this will block
await awaiter;
}
catch (Exception)
{
//cancelled, don't care
}

//if pending isn't null, that means we terminated before ForEachAsync reached it
//execute it
if (pending != null)
{
await pending();
}
});
}


I then use it like this. Here is an example with a button click, b1 is a System.Windows.Forms.Button object. This could be anything. For my test app I was changing the colors in some panels on the main form. Per previous code in OP, tasks is just a List of type Task.



var awaiter1 = b1.WaitableDebouncer(h => b1.Click += h, h => b1.Click -= h, 
scheduler,
canceller.Token,
TimeSpan.FromMilliseconds(5000),
async () =>
{
Invoke(new Action(() =>
{
if (p1.BackColor == Color.Red)
{
p1.BackColor = Color.Orange;
}
else if (p1.BackColor == Color.Orange)
{
p1.BackColor = Color.Yellow;
}
else if (p1.BackColor == Color.Yellow)
{
p1.BackColor = Color.HotPink;
}
else
{
p1.BackColor = Color.Red;
}
}));
});

tasks.Add(awaiter1);


Another for a TextChanged on a text box. t1 is System.Windows.Forms.TextBox. Again this could be anything, I'm just setting a static someValue string variable and updating a label on UI.



var awaiter2 = t1.WaitableDebouncer(h => t1.TextChanged += h, h => t1.TextChanged -= h, 
scheduler,
canceller.Token,
TimeSpan.FromMilliseconds(5000),
async () =>
{
savedValue = t1.Text;

Invoke(new Action(() => l1.Text = savedValue));
});

tasks.Add(awaiter2);


Then this is what termination or shutdown looks like. This could be an application closure, or a file closure. Just some event where we need to unbind these events but save any pending work that has been initiated by the user before doing so. Imagine user typing into the textbox then quickly hitting X to close the app. The 5 seconds has not run out yet.



private async Task AwaitPendingEvents()
{
if (tasks.Count > 0)
{
await Task.WhenAll(tasks);
}
}


We have an app-wide waiting routine. On close we do.



//main cancel signal
canceller.Cancel();

await AwaitPendingEvents();


So far with my tests it appears to work. If no event has ever been generated, it will cancel. If an event has been generated we then look to see if there is any pending work that hasn't made it through the throttle yet. If so, we cancel the observable and execute that pending work ourselves so we don't have to wait on the timer. If there is pending work and we've already made it through the throttle, then we just wait and let the observable subscription finish executing it. The subscription then cancels itself after execution if a cancellation has been requested.






share|improve this answer
























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54029328%2fhow-to-avoid-deadlock-with-observable-fromeventpattern-async-routines%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    0














    Comments from both @Servy and @Enigmativity helped me pin it down. For those interested, here is the solution I came up with. Any suggestions on my approach let me know.



    I created a static helper class named WaitableEventHelper, which includes the following function.



    public static Task WaitableDebouncer(
    this Control c,
    Action<EventHandler> addHandler,
    Action<EventHandler> removeHandler,
    IScheduler scheduler,
    CancellationToken cancelToken,
    TimeSpan limit,
    Func<Task> func)
    {
    var mycts = new CancellationTokenSource();

    bool activated = false;
    bool active = false;

    Func<Task> pending = null;

    var awaiter = Observable.FromEventPattern(addHandler, removeHandler, scheduler)
    .TakeUntil(x => { return cancelToken.IsCancellationRequested; })
    .Do((x) => { activated = true; })
    .Do((x) =>
    {
    //sets pending task to last in sequence
    pending = func;
    })
    .Throttle(limit, scheduler)
    .Do((x) => { active = true; }) //done with throttle
    .ForEachAsync(async (x) =>
    {
    //get func
    var f = pending;

    //remove from list
    pending = null;

    //execute it
    await f();

    //have we been cancelled?
    if (cancelToken.IsCancellationRequested)
    {
    mycts.Cancel();
    }

    //not active
    active = false;

    }, mycts.Token);

    //if cancelled
    cancelToken.Register(() =>
    {
    //never activated, force cancel
    if (!activated)
    {
    mycts.Cancel();
    }

    //activated in the past but not currently active
    if (activated && !active)
    {
    mycts.Cancel();
    }
    });

    //return new awaiter based on conditions
    return Task.Run(async () =>
    {
    try
    {
    //until awaiter finishes or is cancelled, this will block
    await awaiter;
    }
    catch (Exception)
    {
    //cancelled, don't care
    }

    //if pending isn't null, that means we terminated before ForEachAsync reached it
    //execute it
    if (pending != null)
    {
    await pending();
    }
    });
    }


    I then use it like this. Here is an example with a button click, b1 is a System.Windows.Forms.Button object. This could be anything. For my test app I was changing the colors in some panels on the main form. Per previous code in OP, tasks is just a List of type Task.



    var awaiter1 = b1.WaitableDebouncer(h => b1.Click += h, h => b1.Click -= h, 
    scheduler,
    canceller.Token,
    TimeSpan.FromMilliseconds(5000),
    async () =>
    {
    Invoke(new Action(() =>
    {
    if (p1.BackColor == Color.Red)
    {
    p1.BackColor = Color.Orange;
    }
    else if (p1.BackColor == Color.Orange)
    {
    p1.BackColor = Color.Yellow;
    }
    else if (p1.BackColor == Color.Yellow)
    {
    p1.BackColor = Color.HotPink;
    }
    else
    {
    p1.BackColor = Color.Red;
    }
    }));
    });

    tasks.Add(awaiter1);


    Another for a TextChanged on a text box. t1 is System.Windows.Forms.TextBox. Again this could be anything, I'm just setting a static someValue string variable and updating a label on UI.



    var awaiter2 = t1.WaitableDebouncer(h => t1.TextChanged += h, h => t1.TextChanged -= h, 
    scheduler,
    canceller.Token,
    TimeSpan.FromMilliseconds(5000),
    async () =>
    {
    savedValue = t1.Text;

    Invoke(new Action(() => l1.Text = savedValue));
    });

    tasks.Add(awaiter2);


    Then this is what termination or shutdown looks like. This could be an application closure, or a file closure. Just some event where we need to unbind these events but save any pending work that has been initiated by the user before doing so. Imagine user typing into the textbox then quickly hitting X to close the app. The 5 seconds has not run out yet.



    private async Task AwaitPendingEvents()
    {
    if (tasks.Count > 0)
    {
    await Task.WhenAll(tasks);
    }
    }


    We have an app-wide waiting routine. On close we do.



    //main cancel signal
    canceller.Cancel();

    await AwaitPendingEvents();


    So far with my tests it appears to work. If no event has ever been generated, it will cancel. If an event has been generated we then look to see if there is any pending work that hasn't made it through the throttle yet. If so, we cancel the observable and execute that pending work ourselves so we don't have to wait on the timer. If there is pending work and we've already made it through the throttle, then we just wait and let the observable subscription finish executing it. The subscription then cancels itself after execution if a cancellation has been requested.






    share|improve this answer




























      0














      Comments from both @Servy and @Enigmativity helped me pin it down. For those interested, here is the solution I came up with. Any suggestions on my approach let me know.



      I created a static helper class named WaitableEventHelper, which includes the following function.



      public static Task WaitableDebouncer(
      this Control c,
      Action<EventHandler> addHandler,
      Action<EventHandler> removeHandler,
      IScheduler scheduler,
      CancellationToken cancelToken,
      TimeSpan limit,
      Func<Task> func)
      {
      var mycts = new CancellationTokenSource();

      bool activated = false;
      bool active = false;

      Func<Task> pending = null;

      var awaiter = Observable.FromEventPattern(addHandler, removeHandler, scheduler)
      .TakeUntil(x => { return cancelToken.IsCancellationRequested; })
      .Do((x) => { activated = true; })
      .Do((x) =>
      {
      //sets pending task to last in sequence
      pending = func;
      })
      .Throttle(limit, scheduler)
      .Do((x) => { active = true; }) //done with throttle
      .ForEachAsync(async (x) =>
      {
      //get func
      var f = pending;

      //remove from list
      pending = null;

      //execute it
      await f();

      //have we been cancelled?
      if (cancelToken.IsCancellationRequested)
      {
      mycts.Cancel();
      }

      //not active
      active = false;

      }, mycts.Token);

      //if cancelled
      cancelToken.Register(() =>
      {
      //never activated, force cancel
      if (!activated)
      {
      mycts.Cancel();
      }

      //activated in the past but not currently active
      if (activated && !active)
      {
      mycts.Cancel();
      }
      });

      //return new awaiter based on conditions
      return Task.Run(async () =>
      {
      try
      {
      //until awaiter finishes or is cancelled, this will block
      await awaiter;
      }
      catch (Exception)
      {
      //cancelled, don't care
      }

      //if pending isn't null, that means we terminated before ForEachAsync reached it
      //execute it
      if (pending != null)
      {
      await pending();
      }
      });
      }


      I then use it like this. Here is an example with a button click, b1 is a System.Windows.Forms.Button object. This could be anything. For my test app I was changing the colors in some panels on the main form. Per previous code in OP, tasks is just a List of type Task.



      var awaiter1 = b1.WaitableDebouncer(h => b1.Click += h, h => b1.Click -= h, 
      scheduler,
      canceller.Token,
      TimeSpan.FromMilliseconds(5000),
      async () =>
      {
      Invoke(new Action(() =>
      {
      if (p1.BackColor == Color.Red)
      {
      p1.BackColor = Color.Orange;
      }
      else if (p1.BackColor == Color.Orange)
      {
      p1.BackColor = Color.Yellow;
      }
      else if (p1.BackColor == Color.Yellow)
      {
      p1.BackColor = Color.HotPink;
      }
      else
      {
      p1.BackColor = Color.Red;
      }
      }));
      });

      tasks.Add(awaiter1);


      Another for a TextChanged on a text box. t1 is System.Windows.Forms.TextBox. Again this could be anything, I'm just setting a static someValue string variable and updating a label on UI.



      var awaiter2 = t1.WaitableDebouncer(h => t1.TextChanged += h, h => t1.TextChanged -= h, 
      scheduler,
      canceller.Token,
      TimeSpan.FromMilliseconds(5000),
      async () =>
      {
      savedValue = t1.Text;

      Invoke(new Action(() => l1.Text = savedValue));
      });

      tasks.Add(awaiter2);


      Then this is what termination or shutdown looks like. This could be an application closure, or a file closure. Just some event where we need to unbind these events but save any pending work that has been initiated by the user before doing so. Imagine user typing into the textbox then quickly hitting X to close the app. The 5 seconds has not run out yet.



      private async Task AwaitPendingEvents()
      {
      if (tasks.Count > 0)
      {
      await Task.WhenAll(tasks);
      }
      }


      We have an app-wide waiting routine. On close we do.



      //main cancel signal
      canceller.Cancel();

      await AwaitPendingEvents();


      So far with my tests it appears to work. If no event has ever been generated, it will cancel. If an event has been generated we then look to see if there is any pending work that hasn't made it through the throttle yet. If so, we cancel the observable and execute that pending work ourselves so we don't have to wait on the timer. If there is pending work and we've already made it through the throttle, then we just wait and let the observable subscription finish executing it. The subscription then cancels itself after execution if a cancellation has been requested.






      share|improve this answer


























        0












        0








        0







        Comments from both @Servy and @Enigmativity helped me pin it down. For those interested, here is the solution I came up with. Any suggestions on my approach let me know.



        I created a static helper class named WaitableEventHelper, which includes the following function.



        public static Task WaitableDebouncer(
        this Control c,
        Action<EventHandler> addHandler,
        Action<EventHandler> removeHandler,
        IScheduler scheduler,
        CancellationToken cancelToken,
        TimeSpan limit,
        Func<Task> func)
        {
        var mycts = new CancellationTokenSource();

        bool activated = false;
        bool active = false;

        Func<Task> pending = null;

        var awaiter = Observable.FromEventPattern(addHandler, removeHandler, scheduler)
        .TakeUntil(x => { return cancelToken.IsCancellationRequested; })
        .Do((x) => { activated = true; })
        .Do((x) =>
        {
        //sets pending task to last in sequence
        pending = func;
        })
        .Throttle(limit, scheduler)
        .Do((x) => { active = true; }) //done with throttle
        .ForEachAsync(async (x) =>
        {
        //get func
        var f = pending;

        //remove from list
        pending = null;

        //execute it
        await f();

        //have we been cancelled?
        if (cancelToken.IsCancellationRequested)
        {
        mycts.Cancel();
        }

        //not active
        active = false;

        }, mycts.Token);

        //if cancelled
        cancelToken.Register(() =>
        {
        //never activated, force cancel
        if (!activated)
        {
        mycts.Cancel();
        }

        //activated in the past but not currently active
        if (activated && !active)
        {
        mycts.Cancel();
        }
        });

        //return new awaiter based on conditions
        return Task.Run(async () =>
        {
        try
        {
        //until awaiter finishes or is cancelled, this will block
        await awaiter;
        }
        catch (Exception)
        {
        //cancelled, don't care
        }

        //if pending isn't null, that means we terminated before ForEachAsync reached it
        //execute it
        if (pending != null)
        {
        await pending();
        }
        });
        }


        I then use it like this. Here is an example with a button click, b1 is a System.Windows.Forms.Button object. This could be anything. For my test app I was changing the colors in some panels on the main form. Per previous code in OP, tasks is just a List of type Task.



        var awaiter1 = b1.WaitableDebouncer(h => b1.Click += h, h => b1.Click -= h, 
        scheduler,
        canceller.Token,
        TimeSpan.FromMilliseconds(5000),
        async () =>
        {
        Invoke(new Action(() =>
        {
        if (p1.BackColor == Color.Red)
        {
        p1.BackColor = Color.Orange;
        }
        else if (p1.BackColor == Color.Orange)
        {
        p1.BackColor = Color.Yellow;
        }
        else if (p1.BackColor == Color.Yellow)
        {
        p1.BackColor = Color.HotPink;
        }
        else
        {
        p1.BackColor = Color.Red;
        }
        }));
        });

        tasks.Add(awaiter1);


        Another for a TextChanged on a text box. t1 is System.Windows.Forms.TextBox. Again this could be anything, I'm just setting a static someValue string variable and updating a label on UI.



        var awaiter2 = t1.WaitableDebouncer(h => t1.TextChanged += h, h => t1.TextChanged -= h, 
        scheduler,
        canceller.Token,
        TimeSpan.FromMilliseconds(5000),
        async () =>
        {
        savedValue = t1.Text;

        Invoke(new Action(() => l1.Text = savedValue));
        });

        tasks.Add(awaiter2);


        Then this is what termination or shutdown looks like. This could be an application closure, or a file closure. Just some event where we need to unbind these events but save any pending work that has been initiated by the user before doing so. Imagine user typing into the textbox then quickly hitting X to close the app. The 5 seconds has not run out yet.



        private async Task AwaitPendingEvents()
        {
        if (tasks.Count > 0)
        {
        await Task.WhenAll(tasks);
        }
        }


        We have an app-wide waiting routine. On close we do.



        //main cancel signal
        canceller.Cancel();

        await AwaitPendingEvents();


        So far with my tests it appears to work. If no event has ever been generated, it will cancel. If an event has been generated we then look to see if there is any pending work that hasn't made it through the throttle yet. If so, we cancel the observable and execute that pending work ourselves so we don't have to wait on the timer. If there is pending work and we've already made it through the throttle, then we just wait and let the observable subscription finish executing it. The subscription then cancels itself after execution if a cancellation has been requested.






        share|improve this answer













        Comments from both @Servy and @Enigmativity helped me pin it down. For those interested, here is the solution I came up with. Any suggestions on my approach let me know.



        I created a static helper class named WaitableEventHelper, which includes the following function.



        public static Task WaitableDebouncer(
        this Control c,
        Action<EventHandler> addHandler,
        Action<EventHandler> removeHandler,
        IScheduler scheduler,
        CancellationToken cancelToken,
        TimeSpan limit,
        Func<Task> func)
        {
        var mycts = new CancellationTokenSource();

        bool activated = false;
        bool active = false;

        Func<Task> pending = null;

        var awaiter = Observable.FromEventPattern(addHandler, removeHandler, scheduler)
        .TakeUntil(x => { return cancelToken.IsCancellationRequested; })
        .Do((x) => { activated = true; })
        .Do((x) =>
        {
        //sets pending task to last in sequence
        pending = func;
        })
        .Throttle(limit, scheduler)
        .Do((x) => { active = true; }) //done with throttle
        .ForEachAsync(async (x) =>
        {
        //get func
        var f = pending;

        //remove from list
        pending = null;

        //execute it
        await f();

        //have we been cancelled?
        if (cancelToken.IsCancellationRequested)
        {
        mycts.Cancel();
        }

        //not active
        active = false;

        }, mycts.Token);

        //if cancelled
        cancelToken.Register(() =>
        {
        //never activated, force cancel
        if (!activated)
        {
        mycts.Cancel();
        }

        //activated in the past but not currently active
        if (activated && !active)
        {
        mycts.Cancel();
        }
        });

        //return new awaiter based on conditions
        return Task.Run(async () =>
        {
        try
        {
        //until awaiter finishes or is cancelled, this will block
        await awaiter;
        }
        catch (Exception)
        {
        //cancelled, don't care
        }

        //if pending isn't null, that means we terminated before ForEachAsync reached it
        //execute it
        if (pending != null)
        {
        await pending();
        }
        });
        }


        I then use it like this. Here is an example with a button click, b1 is a System.Windows.Forms.Button object. This could be anything. For my test app I was changing the colors in some panels on the main form. Per previous code in OP, tasks is just a List of type Task.



        var awaiter1 = b1.WaitableDebouncer(h => b1.Click += h, h => b1.Click -= h, 
        scheduler,
        canceller.Token,
        TimeSpan.FromMilliseconds(5000),
        async () =>
        {
        Invoke(new Action(() =>
        {
        if (p1.BackColor == Color.Red)
        {
        p1.BackColor = Color.Orange;
        }
        else if (p1.BackColor == Color.Orange)
        {
        p1.BackColor = Color.Yellow;
        }
        else if (p1.BackColor == Color.Yellow)
        {
        p1.BackColor = Color.HotPink;
        }
        else
        {
        p1.BackColor = Color.Red;
        }
        }));
        });

        tasks.Add(awaiter1);


        Another for a TextChanged on a text box. t1 is System.Windows.Forms.TextBox. Again this could be anything, I'm just setting a static someValue string variable and updating a label on UI.



        var awaiter2 = t1.WaitableDebouncer(h => t1.TextChanged += h, h => t1.TextChanged -= h, 
        scheduler,
        canceller.Token,
        TimeSpan.FromMilliseconds(5000),
        async () =>
        {
        savedValue = t1.Text;

        Invoke(new Action(() => l1.Text = savedValue));
        });

        tasks.Add(awaiter2);


        Then this is what termination or shutdown looks like. This could be an application closure, or a file closure. Just some event where we need to unbind these events but save any pending work that has been initiated by the user before doing so. Imagine user typing into the textbox then quickly hitting X to close the app. The 5 seconds has not run out yet.



        private async Task AwaitPendingEvents()
        {
        if (tasks.Count > 0)
        {
        await Task.WhenAll(tasks);
        }
        }


        We have an app-wide waiting routine. On close we do.



        //main cancel signal
        canceller.Cancel();

        await AwaitPendingEvents();


        So far with my tests it appears to work. If no event has ever been generated, it will cancel. If an event has been generated we then look to see if there is any pending work that hasn't made it through the throttle yet. If so, we cancel the observable and execute that pending work ourselves so we don't have to wait on the timer. If there is pending work and we've already made it through the throttle, then we just wait and let the observable subscription finish executing it. The subscription then cancels itself after execution if a cancellation has been requested.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Jan 4 at 17:37









        AndrewAndrew

        13




        13
































            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54029328%2fhow-to-avoid-deadlock-with-observable-fromeventpattern-async-routines%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Angular Downloading a file using contenturl with Basic Authentication

            Olmecas

            Can't read property showImagePicker of undefined in react native iOS