Bug 16355 - Each call to SemaphoreSlim.WaitAsync() yields a new Thread
Summary: Each call to SemaphoreSlim.WaitAsync() yields a new Thread
Status: RESOLVED INVALID
Alias: None
Product: Android
Classification: Xamarin
Component: Mono runtime / AOT Compiler ()
Version: 4.10.1
Hardware: PC Mac OS
: --- normal
Target Milestone: ---
Assignee: Marek Safar
URL:
Depends on:
Blocks:
 
Reported: 2013-11-20 04:23 UTC by Prashant Cholachagudda
Modified: 2017-08-07 20:45 UTC (History)
6 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
Test case (41.31 KB, application/zip)
2013-11-20 04:23 UTC, Prashant Cholachagudda
Details


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED INVALID

Description Prashant Cholachagudda 2013-11-20 04:23:06 UTC
Created attachment 5480 [details]
Test case

Each call to SemaphoreSlim.WaitAsync on Xamarin.Android creates a new Thread, however it does not happen on .Net/Mono desktop profiles.
Comment 1 Jonathan Pryor 2013-11-20 11:14:09 UTC
The test isn't entirely identical between the Console and Android versions. If I modify SemaphoreSlimAsync/Activity1.cs (the Android version) so that OnCreate() calls the async method (just like Main() in the Console version calls TestMethod()), the thread count is _stable_:

    // Modify OnCreate():
    var test = string.Format(" Start {0} threads!",
        System.Diagnostics.Process.GetCurrentProcess().Threads.Count);
    Console.WriteLine (test);
    for (int i = 0; i < 15; i++) {
      TestMethod ();
    }

    // New Activity1 method:
    async void TestMethod()
    {
      var test = string.Format("{0} threads!", System.Diagnostics.Process.GetCurrentProcess().Threads.Count);
      Console.WriteLine (test);
      await semaphore.WaitAsync();
    }

`adb logcat` output:

I/mono-stdout(30713):  Start 11 threads!
I/mono-stdout(30713): 11 threads!
I/mono-stdout(30713): 13 threads!
I/mono-stdout(30713): 13 threads!
I/mono-stdout(30713): 13 threads!
I/mono-stdout(30713): 13 threads!
I/mono-stdout(30713): 13 threads!
I/mono-stdout(30713): 13 threads!
I/mono-stdout(30713): 13 threads!
I/mono-stdout(30713): 13 threads!
I/mono-stdout(30713): 13 threads!
I/mono-stdout(30713): 13 threads!
I/mono-stdout(30713): 13 threads!
I/mono-stdout(30713): 13 threads!
I/mono-stdout(30713): 13 threads!
I/mono-stdout(30713): 13 threads!

So we grow a couple, but then thread use stabilizes. This seems acceptable to me.

Where things go wrong is when you click the Button -- _then_ the thread count constantly increases.

Start under gdb, and most (all?) of the threads have stack traces of:

> Thread 18 (Thread 31088):
> #0  0x40118590 in __futex_syscall3 () from /Users/jon/Downloads/bxc-16355/SemaphoreSlimAsync/SemaphoreSlimAsync/gdb-symbols/libc.so
> #1  0x4010a6ac in __pthread_cond_timedwait_relative ()
>    from /Users/jon/Downloads/bxc-16355/SemaphoreSlimAsync/SemaphoreSlimAsync/gdb-symbols/libc.so
> #2  0x4010a70c in __pthread_cond_timedwait ()
>    from /Users/jon/Downloads/bxc-16355/SemaphoreSlimAsync/SemaphoreSlimAsync/gdb-symbols/libc.so
> #3  0x732949cc in _wapi_handle_timedwait_signal_handle (handle=0x408, timeout=0x7bd6d8f8, alertable=1, poll=<optimized out>)
>     at /Users/jon/Development/xamarin/mono/mono/io-layer/handles.c:1586
> #4  0x732a51e0 in WaitForSingleObjectEx (handle=0x408, timeout=1, alertable=1)
>     at /Users/jon/Development/xamarin/mono/mono/io-layer/wait.c:198
> #5  0x7322c7e4 in mono_wait_uninterrupted (thread=0x77e87d40, multiple=<optimized out>, numhandles=1, handles=0x7bd6d974, waitall=0, 
>     ms=1, alertable=<optimized out>) at /Users/jon/Development/xamarin/mono/mono/metadata/threads.c:1490
> #6  0x7322ca38 in ves_icall_System_Threading_WaitHandle_WaitOne_internal (this=<optimized out>, handle=0x77df1758, ms=1, 
>     exitContext=<optimized out>) at /Users/jon/Development/xamarin/mono/mono/metadata/threads.c:1622
> #7  0x782a64ac in ?? ()
> #8  0x782a64ac in ?? ()
> 
> (gdb) p mono_pmip(0x782a64ac)
> $3 = 0x7a746b00 " (wrapper managed-to-native) System.Threading.WaitHandle:WaitOne_internal (System.Threading.WaitHandle,intptr,int,bool) + 0x64 (0x782a6448 0x782a64f8) [0x7305a360 - RootDomain]"

Modify the button.Click event handler to print `new StackTrace()` to `logcat`, and:

> I/mono-stdout(31205): # button click!
> I/mono-stdout(31205):    at SemaphoreSlimAsync.Activity1+<OnCreate>c__AnonStorey2+<OnCreate>c__async1.MoveNext()
> I/mono-stdout(31205):    at System.Runtime.CompilerServices.AsyncVoidMethodBuilder.Start(<OnCreate>c__async1 ByRef stateMachine)
> I/mono-stdout(31205):    at SemaphoreSlimAsync.Activity1+<OnCreate>c__AnonStorey2.<>m__0(System.Object , System.EventArgs )
> I/mono-stdout(31205):    at Android.Views.View+IOnClickListenerImplementor.OnClick(Android.Views.View v)
> I/mono-stdout(31205):    at Android.Views.View+IOnClickListenerInvoker.n_OnClick_Landroid_view_View_(IntPtr jnienv, IntPtr native__this, IntPtr native_v)
> I/mono-stdout(31205):    at System.Object.2ddacf22-9ac8-4cb1-b337-f556ee7e680f(IntPtr , IntPtr , IntPtr )

...which may not be very helpful.

At this point I've exhausted my async debugging faculties & knowledge.

marek: Any idea why the thread count keeps increasing in the button.Click event handler? Anything else I should investigate?
Comment 2 guillaume.moissaing 2013-11-20 11:50:05 UTC
I still have the bug with a nammed async method instead of the async delegate, you have to wait (2sec for instance) between each click. The time the thread starts...

That may help :
https://github.com/mono/mono/blob/a31c107f59298053e4ff17fd09b2fa617b75c1ba/mcs/class/corlib/System.Threading/SemaphoreSlim.cs

                public Task WaitAsync ()
                {
                        return Task.Factory.StartNew (() => Wait ());
                }


Mono implementation of WaitAsync starts a new Task on the thread pool for each call. If 200 calls are pending, 200 threads are started and blocked in a Wait !
Another implementation might rely on a queue of TaskCompletionSource with value setted in Semaphore.Release. That's what I did waiting for an official fix.
Comment 3 Jon Douglas [MSFT] 2017-08-07 20:45:15 UTC
Thank you for taking the time to submit this report. After reviewing the description of this bug, we believe it no longer affects the current version of Xamarin.Android. If you are still experiencing the issue after updating your packages, please reopen this report with an attached reproduction.