Runtime: System.Threading.Thread should support all runtimes

Created on 31 Jul 2015  Â·  55Comments  Â·  Source: dotnet/runtime

The current System.Threading.Thread (and System.Threading.ThreadPool) packages only support desktop and CoreCLR.

The problem is that with a name like System.Threading.* and with threads being a core part of many apps, people won't know (or care!) that UWP apps will lose out on that library because only Task is supported.

The best solution is to implement Thread/ThreadPool for UWP so that people can use the threading model they're most comfortable with and what's most appropriate for the job. Forcing Task for UWP is counterproductive if it'll mean that UWP will lose out on many libraries that choose to use Thread anyway.

When it comes to creation/consumption of .NET Core packages, right now ASPNet is the biggest driver. As much as we want people to use UWP, it's just smaller for now. That puts even greater pressure on UWP as library authors will either not know that Thread isn't available on UWP or care even if they do.

.NET Core is supposed to be unifying the BCL and shielding libraries from platform/runtime differences. Please don't fragment it with something as central as Thread.

area-System.Threading enhancement

Most helpful comment

Why do you say that Tasks are a poor alternative for you? What's wrong with TaskCreationOptions.LongRunning, as mentioned above?

This is the logical equivalent of saying that we don't need integers because all floats can be treated like integers.

All 55 comments

Why not just used the Task, Parallel Lib or use Parrallel for passed a list
of objects in that way you don't need to pool your self.

On Thu, Jul 30, 2015 at 10:57 PM, Oren Novotny [email protected]
wrote:

The current System.Threading.Thread (and System.Threading.ThreadPool)
packages only support desktop and CoreCLR.

The problem is that with a name like System.Threading.* and with threads
being a core part of many apps, people won't know (or care!) that UWP apps
will lose out on that library because only Task is supported.

The best solution is to implement Thread/ThreadPool for UWP so that people
can use the threading model they're most comfortable with. Forcing Task for
UWP is counterproductive if it'll mean that UWP will lose out on many
libraries that choose to use Thread anyway.

When it comes to creation/consumption of .NET Core packages, right now
ASPNet is the biggest driver. As much as we want people to use UWP, it's
just smaller for now. That puts even greater pressure on UWP as library
authors will either not know that Thread isn't available on UWP or care
even if they do.

.NET Core is supposed to be unifying the BCL and shielding libraries from
platform/runtime differences. Please don't fragment it with something as
central as Thread.

—
Reply to this email directly or view it on GitHub
https://github.com/dotnet/corefx/issues/2576.

_Rafi QadriSoftware Engineer240-330-7827Email Security Code=00101_

@rqadri133 There are two issues here:

"Why not just use Task" - this is a style thing. If the Thread package exists in stable as it does in beta, people will use it because they like/prefer to use thread.

If System.Threading.Thread will exist at all, and so far it's on the list to be ported, then it has to work for everything. The current beta packages for it do not.

So I'd say either make thread work everywhere or force everyone on .net core to use Task. Threading has to work everywhere with the same primitives.

/cc @ericeil

Task is a poor replacement for Thread.

A thread is a discrete unit of execution. A task is not. You can't build a thread pool with tasks because the level of abstraction is wrong.

You can't build a thread pool with tasks because the level of abstraction is wrong.

FWIW, you can, actually: by passing TaskCreationOptions.LongRunning and TaskScheduler.Default to StartNew, a dedicated thread will be created for that one Task instance. To be fair, that's the current behavior and it's not documented as such, but I doubt it would change in the future due to a fair amount of code that has taken a dependency on it.

@stephentoub This is good to know, but I think it also misses the point that threading is something that should be available on all platforms without using undocumented Task hacks to simulate it.

What if we defined a new option, TaskCreationOptions.DedicatedThread or somesuch. Would that address this concern?

Or just document what LongRunning means for the default scheduler.

That's fine, long as you don't bring Thread over. My main point in this is that if you bring Thread over, it has to be for all runtimes or not at all. The latter would cause more pain as it'd force existing Thread-compatible code to be rewritten for Task/Async unnecessarily.

@onovotny, I'm having trouble following the argument. It seems your concern isn't specific to threads, but rather is a general request that a contract should only be implemented in .NET Core if it's also implemented for every possible .NET implementation on any device on any platform? Is that correct? Otherwise, I don't see the logic behind saying that it's sufficient for mechanism X to be available everywhere unless mechanism Y is also available but only in some places.

@stephentoub As stated in my original issue posting, I believe that Thread is a core type that should be available for every .NET implementation. There are some contracts/BCL packages for .NET Core that may indeed not support UWP or DNX, etc, but those should be the exceptions and not core primitives.

My concern is ecosystem/library fragmentation. People will write packages that depend on Thread (because they like it over tasks and it's more compatible with their existing codebase). Those packages would be unavailable to UWP projects, perhaps unintentionally.

My bottom-line point is that Thread/Task is an arbitrary split, that C++ apps for Win10/Store _do_ allow Threads, not just tasks, so a primitive like Thread needs to be on all platforms.

I have to concur we really need Thread in all runtimes including .NET core. Threads are available on linux, macos, windows etc. And Tasks are a really poor alternative, we almost always use very long running (almost always entire app lifetime even) threads to compose our applications. Applications that could run on Linux.

@nietras Why do you say that Tasks are a poor alternative for you? What's wrong with TaskCreationOptions.LongRunning, as mentioned above?

Yes, please, we really do need Thread in .NET Core.
Looking at the history of Asynchronous Design Patterns in .NET, there have been three major iterations. (Does IObservable count?).

The TPL and async/await is pretty cool but who knows what the next hot pattern will be.
Providing access to threads allows developers to explore other asynchronous/parallelism patterns without being boxed into TPL/TAP.

Why do you say that Tasks are a poor alternative for you? What's wrong with TaskCreationOptions.LongRunning, as mentioned above?

This is the logical equivalent of saying that we don't need integers because all floats can be treated like integers.

@bradwilson There would be significant practical issues with trying to use floats as integers (you lose performance, you lose precision, your code becomes much more verbose).

As far as I can see, the primary concern here is conceptual, not practical. That's still a good point, but I think it makes it much lower priority.

@svick there are many things wrong with using Task instead of Thread, you can't set thread. priority, thread name, apartment etc. Additionally, Task API makes no promise a long running will result in a new thread.

I would compare Thread to Task as task meaning taking a bite of a sandwich picked up from the floor... and Thread to making it yourself, eating it and cleaning up after. There are different concepts. Task tries to define a specific bite of work to be completed, while Thread defines a context within which to complete work.

Ping? I can see that the latest System.Threading.Thread package in the dotnet-core NuGet feed hasn't changed this picture.

Just as reminder... What is the implementation state of Thread in net.core? Porting of existing libs to .NET is very difficult if we have to target Task-style. Having 'Thread' is MUST.

Ping?

What work would need to be done to support this? Is there UWP support that has to be added; is it purely managed code? Is this something "we" can do considering that the code itself already exists? We would not look to change any of the code area to support UWP.

Maybe a better question is this: is any version of System.Threading.Thread going to ship for 1.0? Or is it just a placeholder in the source for now.

I'm just going to +1 this. Task and thread are different primitives and should be treated such.

I don't understand why you removed System.Threading.Thread. Just as mentioned above, task and thread are different primitives, and not all work can be performed perfectly with Task. An example is that when we use the ChakraCore in a UWP app, the runtime object is thread-based, and all execution contexts associated with a runtime must be executed on one thread. Maybe the Task can implement the requirement, but a Thread is the best choose.

I'm trying to write a method for a PCL where it will spawn a thread or likewise which eventually set result for a task which is being depended by a property, and this happens:

  1. the task must be waited on via Result property since a property getter can't be async
  2. no matter what the "setter" logic does it must be running on another thread and never reenter the original calling thread, or deadlock happens
  3. by deselecting Silverlight support the PLT adds Core FX support automatically
  4. no Thread, doomed

Technically this only blocks me from testing and, I can break my project down to pieces to get it work, but guess what?
I'd rather add Silverlight support back and Install-Package Microsoft.Bcl.Async

edit: Found the way to get my code work, but I still want Thread or ThreadPool

MSFT has a habit of enticing us to adopt their "latest, greatest stuff".. First it was WPF, then Silverlight,, MVC and now UWP. The deeper we dove into this stuff we never found utopia, in fact we found a lot of half-baked incomplete solutions to very important things. Not to mention "Write once run anywhere". If UWP is "Write once run anywhere" then why is it dumbed down to the lowest common denominator (the cell phone)? MFST has lost a lot of credibility with their own adopters! This is a perfect example.

This would fall out of bringing UWP up to Net Standard 2.0

I have a large collection of HPC libraries I've written for .NET that I'm now trying to get into portable libraries. Not having thread means this effort is dead in the water as it's pointless to have a portable class library for desktop and core, while being incompatible with UWP. The effort involved in translating to task would be enormous, and probably not even possible knowing how extensive and deep the dependencies are on Thread.

Thread is a basic operating system primitive with significantly different properties and abstraction than Task in .NET. Even further thread is a basic concept of operating system built into silicon by Intel/AMD for x86 and ARM for their respective ISAs (except for microcontrollers). Concepts of thread context, context switching and symmetric multithreading are based on physical thread implementation in silicon and it is must for OS to abstract them and expose to software stack. System.Threading.Thread provides access to some of OS abstracted properties and OS specific functionality and fortunately equally well will work on any OS that is based on "silicon" threads and currently supported by .NET Core. Cutting off developers from such basic OS building block by enforcing Task usage for parallel processing is wrong from its very principle of isolating developers from basic OS building blocks. Such decisions limit software development scope on given framework to some less demanding domains. I would like to see .NET Core to compete with Java on all platforms, otherwise it's waste of time from my perspective to port anything to it.

On the other hand I fully understand and support decisions to remove application domains, binary serialization and remoting which were never very useful (perhaps if runtime will free assembly files after loading code - like in nixes - this would make life even easier after getting rid of assembly domains) ,

Please respect our work and do not make decisions which override basic programming primitives with new "smarts". If there are new features which are even "very great" do not remove underlying features which are at the same time very basic for any seasoned developer who writes a bit more code than a simple store apps. Furthermore many developers can write code in different languages targeting different frameworks. If Microsoft blocks access to some basic functionality in .NET Core for UWP developers will find it in different places (i.e. thread Win32 API functions are available from UWP apps so I could use them easily from C++). In fact my last UWP project is mixed code in C# and C++.

+100

Task is good for general purpose but can not replace value of threads. Threads provide granular control over what you want to execute and how. Please give developers the tool what they want, not what MSFT want. Windows 8 is best example if MSFT want to learn some lesson.

It turns out Windows 10 is not what I want on my Surface devices.

@karelz What is the status of this given https://github.com/dotnet/corefx/pull/13569 has been merged in?

@kouvel do you know if there is more left to do? Is it tied to .NET Standard 2.0 on UWP? (as suggested above - https://github.com/dotnet/corefx/issues/2576#issuecomment-249425171)

Yes this is tied to bringing up NS2.0. We are currently working on enabling Thread and ThreadPool for CoreRT, which is a step in this direction.

Apparently we cannot add System.Threading.Thread package without picking up updated versions of other framework packages. Working on that.

@onovotny to clarify the overall .NET Standard 2.0 on UWP story -- it is the next big thing we plan to tackle (there's lots of work there - infra, missing APIs, AOT specifics, etc.) We're trying to finish .NET Standard 2.0 for .NET Core first (still some work left there - few features, stabilization, etc.).

Adding that I have the same problem as mematrix.

https://github.com/dotnet/corefx/issues/2576#issuecomment-202071343

In my UWP app, I have a Chakra run time. I want to run the JS off of the main thread. Chakra requires a "context" to be made available. This "context" is only usable in the thread from which it was created. Using System.Threading.Tasks.Task.Run, I am not able to control which thread my Chakra calls run on. So it is impossible to use Chakra off of the main GUI thread in UWP apps.

@augustl If you use Task.Factory.StartNew with TaskCreationOptions.LongRunning that will create a separate thread to run the created task. You could also use AsyncContext from https://github.com/StephenCleary/AsyncEx/wiki/AsyncContext which uses that internally to create a single threaded SynchronizationContext.

@alexperovich interesting! If nothing else, I can at least implement an event loop in this separate long running thread and communicate to the GUI via queues. Thanks for the info!

For the curious, I did some digging in React Native for UWP to see what they do. Essentially, it boils down to what I described - a simple event loop based on queues. The gist of it is:

var _queue = new BlockingCollection<Action>();

Task.Run(() => {
    while (true) {
        var action = _queue.Take();
        action();
    }
})

It runs all Chakra JS inside one of these MessageQueueThread.SingleBackgroundMessageQueueThread instances here: https://github.com/ReactWindows/react-native-windows/blob/cf7a3013377defcaa57f2c05baf6d90c5a8862d6/ReactWindows/ReactNative.Shared/Bridge/Queue/MessageQueueThread.cs#L198

The only downside I can see to this would be that you can no longer use "await" and do a Task.Run for each job, and get "RPC like" semantics, you need to structure your app around message queues instead. Which one might say could be considered a good idea anyway :)

no point to argue. we need threads in UWP. when can you deliver?

I think this may be part of .NET Standard 2.0 for UWP work -- which is milestone 2.1 (see the milestone details for current estimation of last FI into release date)

@kouvel can you please confirm if it will be part of 2.1 work?

I believe that is the current target, CC @AntonLapounov, @sergiy-k

To be clear -- I think we want the same System.Threading.Thread functionality supported on all platforms. For example, Thread.MemoryBarrier(), BeginCriticalRegion(), BeginThreadAffinity(), SpinWait(int), VolatileRead/Write(ref), [Named]DataSlot, and so on.

This work (Thread for UWP) happens in the CoreRT repo (https://github.com/dotnet/corert). It is part of the .NET Standard 2.0 work. You are very welcome to contribute if you have some time. :)

We've blogged at length about this issue (and the dangers of fragmenting the still-fragile, nubile .NET Standard ecosystem), and I've also opened a bug regarding the fact that the Microsoft-provided System.Threading.Thread package on NuGet claims to support .NET Standard 1.3 while it explicitly does not support UWP (which is a valid .NET Standard 1.4 implementation). In the meantime, TaskThreads is an open source library that mostly implements System.Threading.Thread for UWP targets, and is available on NuGet for those that would like.

To clarify, since this seems to be the place to do so, whether or not System.Threading.Thread supports UAP/UWP is one discussion, but we should also be having another (and, imho, more important) discussion about why this package, which does not support UWP, is labelled as being compatible with .NET Standard 1.3.

If the developers of this package at Microsoft decide that UWP will forever be barred from having a blessed System.Threading.Thread package, so be it. But why claim that this STT package supports .NET Standard 1.3 it it doesn't?

Until such a time where STT binaries are available for UWP 10 in the STT package, the STT nuspec should be changed to read from from .NETStandard1.3 to .NETCore1.0, because as it currently stands, people are using this package and their libraries and projects thinking they are maintaining compatibility with .NET Standard 1.3 and UWP 10.0, but in reality, their packages will fail to install because STT absolutely does not support .NET Standard 1.3 per the definition of the standard.

Should this (please!) happen, you'll find that a lot of disgruntled developers will wake up the next morning to realize that their packages no longer support .NET Standard 1.3 like they thought they did the day before - which is fine, because then they will explicitly make the choice to either a) use tasks instead of threads, which certain parties seem keen on forcing people to do, or b) similarly drop support for .NET Standard 1.3 and support only .NET Core 1.0 just like this package, or c) use an alternative implementation of STT like TaskThreads to provide System.Threading.Thread support on either only UWP while continuing to use the MSFT-provided STT on .NET Core or drop the MSFT-STT dependency entirely and use TaskThreads or similar for both .NET Core and UAP/UWP targets.

Any of these three options is preferrable, imho, to risking the fragmentation of .NET Standard before it's even had a chance, especially with as core of a namespace/package as STT.

(A fourth option exists, which is to change the STT package to target .NET Standard 1.5 until UWP/UAP vNext is released.. or until UAP/UWP officially stops being a first-class .NET Standard platform, as some seem to feel is appropriate.)

@AntonLapounov @kouvel what specifically remains here after our recent work? anything?

@AntonLapounov this is done right? for uwp.next.

OK, System.Thread is in .,NET Standard 2.0 which .NET Core 2.0 will support and we expect the next iteration of UWP to support.

@weshaggard can you help address this comment though: https://github.com/dotnet/corefx/issues/2576#issuecomment-300032695

cc @ericstj

@weshaggard can you help address this comment though: dotnet/corefx#2576 (comment)

This is a result of a decision we made originally to have the package be opt-out instead of opt-in. When a library can build against netstandard but may not work on all platforms you need to decide whether to provide the asset as netstandard ref and then add an opt-out by excluding the asset in the runtime for a given platform like UWP, or you have to not have a netstandard asset but instead only have the opt-in set of refs for the set of platforms that support it. Either way you go there are different trade-offs. However we have since learned that using the opt-out mechanism like we did in this case causes more trouble and so we are no longer doing that with our packages (as in there should never be a missing runtime asset for any package that installs).

Of course there are still cases where the runtime asset simply throws PlatformNotSupported Exceptions for all APIs and so folks still need to test on any platform they wish to support. We are also planning to help with these sort of edges with a tool similar to https://github.com/terrajobst/platform-compat.

@mqudsi the Task-based Thread library would be nice to come with a ThreadPool one too. Tried the DedicatedThreadPool from github, probably that could be a candidate to adapt and use.

in case you've also been confused regarding UWP and Thread, this clarifies the situation and future:

.NET Standard 2.0 will have Thread
.NET Standard 1.3 doesn't really support Thread; the package doesn't provide an implementation for all platforms.

(Our package authoring is complicated. In a nutshell, supporting means a package has to provide a compile time artifact and a deployment artifact. The good old lib folder did both, but we had to expand that for us in order to provide diffferent implementations based on OS, architecture, and TFM.)

With respect to UWP:

UWP currently only supports .NET Standard 1.4
Our goal is to eventually extend UWP to also implement .NET Standard 2.0. Once that happens, UWP will also support Thread.

@danmosemsft, can this be closed now?

@tarekgh?

@kouvel I think we can just close this one now.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Timovzl picture Timovzl  Â·  3Comments

iCodeWebApps picture iCodeWebApps  Â·  3Comments

omariom picture omariom  Â·  3Comments

yahorsi picture yahorsi  Â·  3Comments

nalywa picture nalywa  Â·  3Comments