Skip to content

Commit d58bfe8

Browse files
authored
Merge pull request #792 from microsoft/dev/lifengl/joinableTaskCleanup
JoinTillEmptyAsync hangs for ref-counted JTF collection
2 parents f1c0bb1 + a1d8b02 commit d58bfe8

File tree

3 files changed

+24
-5
lines changed

3 files changed

+24
-5
lines changed

src/Microsoft.VisualStudio.Threading/JoinableTask.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -995,7 +995,7 @@ internal void OnQueueCompleted()
995995

996996
foreach (IJoinableTaskDependent? collection in this.dependencyParents)
997997
{
998-
JoinableTaskDependencyGraph.RemoveDependency(collection, this);
998+
JoinableTaskDependencyGraph.RemoveDependency(collection, this, forceCleanup: true);
999999
}
10001000

10011001
if (this.mainThreadJobSyncContext is object)

src/Microsoft.VisualStudio.Threading/JoinableTaskDependencyGraph.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,11 @@ internal static JoinableTaskCollection.JoinRelease AddDependency(IJoinableTaskDe
7171
/// </summary>
7272
/// <param name="taskItem">The current joinableTask or collection.</param>
7373
/// <param name="child">The <see cref="IJoinableTaskDependent"/> to join as a child.</param>
74-
internal static void RemoveDependency(IJoinableTaskDependent taskItem, IJoinableTaskDependent child)
74+
/// <param name="forceCleanup">Ignore refCount, it is being used when the child task is completed.</param>
75+
internal static void RemoveDependency(IJoinableTaskDependent taskItem, IJoinableTaskDependent child, bool forceCleanup = false)
7576
{
7677
Requires.NotNull(taskItem, nameof(taskItem));
77-
JoinableTaskDependentData.RemoveDependency(taskItem, child);
78+
JoinableTaskDependentData.RemoveDependency(taskItem, child, forceCleanup);
7879
}
7980

8081
/// <summary>
@@ -400,7 +401,8 @@ internal static JoinableTaskCollection.JoinRelease AddDependency(IJoinableTaskDe
400401
/// </summary>
401402
/// <param name="parentTaskOrCollection">The current joinableTask or collection contains to remove a dependency.</param>
402403
/// <param name="joinChild">The <see cref="IJoinableTaskDependent"/> to join as a child.</param>
403-
internal static void RemoveDependency(IJoinableTaskDependent parentTaskOrCollection, IJoinableTaskDependent joinChild)
404+
/// <param name="forceCleanup">Ignore refCount, it is being used when the child task is completed.</param>
405+
internal static void RemoveDependency(IJoinableTaskDependent parentTaskOrCollection, IJoinableTaskDependent joinChild, bool forceCleanup)
404406
{
405407
Requires.NotNull(parentTaskOrCollection, nameof(parentTaskOrCollection));
406408
Requires.NotNull(joinChild, nameof(joinChild));
@@ -412,7 +414,7 @@ internal static void RemoveDependency(IJoinableTaskDependent parentTaskOrCollect
412414
{
413415
if (data.childDependentNodes is object && data.childDependentNodes.TryGetValue(joinChild, out int refCount))
414416
{
415-
if (refCount == 1)
417+
if (refCount == 1 || forceCleanup)
416418
{
417419
joinChild.OnRemovedFromDependency(parentTaskOrCollection);
418420

test/Microsoft.VisualStudio.Threading.Tests/JoinableTaskCollectionTests.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,4 +196,21 @@ public void JoinDisposedTwice()
196196
return Task.CompletedTask;
197197
});
198198
}
199+
200+
[Fact]
201+
public void JoinTillEmptyWorksWithRefCounting()
202+
{
203+
var finishTaskEvent = new AsyncManualResetEvent();
204+
JoinableTask task = this.JoinableFactory.RunAsync(async delegate { await finishTaskEvent.WaitAsync().ConfigureAwait(false); });
205+
206+
var collection = new JoinableTaskCollection(this.context, refCountAddedJobs: true);
207+
208+
collection.Add(task);
209+
collection.Add(task);
210+
211+
finishTaskEvent.Set();
212+
213+
Task waiter = collection.JoinTillEmptyAsync();
214+
Assert.True(waiter.Wait(UnexpectedTimeout));
215+
}
199216
}

0 commit comments

Comments
 (0)