dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.15k stars 4.71k forks source link

System.Threading.Thread should support all runtimes #14946

Closed clairernovotny closed 4 years ago

clairernovotny commented 9 years ago

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.

rqadri133 commented 9 years ago

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 notifications@github.com 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

clairernovotny commented 9 years ago

@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.

ericstj commented 9 years ago

/cc @ericeil

bradwilson commented 9 years ago

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.

stephentoub commented 9 years ago

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.

bradwilson commented 9 years ago

@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.

ericeil commented 9 years ago

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

stephentoub commented 9 years ago

Or just document what LongRunning means for the default scheduler.

clairernovotny commented 9 years ago

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.

stephentoub commented 9 years ago

@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.

clairernovotny commented 9 years ago

@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.

nietras commented 8 years ago

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.

svick commented 8 years ago

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

tenor commented 8 years ago

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.

bradwilson commented 8 years ago

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.

svick commented 8 years ago

@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.

nietras commented 8 years ago

@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.

clairernovotny commented 8 years ago

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

ddobric commented 8 years ago

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.

clairernovotny commented 8 years ago

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.

clairernovotny commented 8 years ago

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.

davidfowl commented 8 years ago

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

mematrix commented 8 years ago

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.

Licshee commented 8 years ago

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

AcousticGuitar commented 8 years ago

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.

danmoseley commented 8 years ago

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

Inquisitorrent commented 8 years ago

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.

4creators commented 8 years ago

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

saleem-mirza commented 8 years ago

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.

Licshee commented 7 years ago

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

clairernovotny commented 7 years ago

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

karelz commented 7 years ago

@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)

kouvel commented 7 years ago

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.

AntonLapounov commented 7 years ago

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

karelz commented 7 years ago

@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.).

augustl commented 7 years ago

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.

alexperovich commented 7 years ago

@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.

augustl commented 7 years ago

@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!

augustl commented 7 years ago

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 :)

maxima120 commented 7 years ago

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

karelz commented 7 years ago

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?

kouvel commented 7 years ago

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

BKStrelioff commented 7 years ago

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.

sergiy-k commented 7 years ago

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. :)

mqudsi commented 7 years ago

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.

mqudsi commented 7 years ago

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.)

danmoseley commented 7 years ago

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

danmoseley commented 7 years ago

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

danmoseley commented 7 years ago

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

weshaggard commented 7 years ago

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.