SlideShare a Scribd company logo
1 of 30
Download to read offline
The 3 VS Threading Rules
WATCH THE VIDEO OF THE ORIGINAL PRESENTATION
The history of RPC calls, p. 1
 RPC = Remote Procedure Call
 It blocks the calling thread, sends a high priority message to the UI thread and
only unblocks the calling thread after the UI thread processes the message.
 Allows the caller to remain unaware of threading requirements of the COM object
it is invoking.
 Is often used in scenarios where you have code that kicks off background thread
work and blocks the UI thread on its completion, since RPC can penetrate the
blocking wait so that the background thread work can use the UI thread as part
of its work.
The history of RPC calls, p. 2
 Implicitly used whenever native or managed code calls a COM object
implemented in native code (roughly).
 Also explicitly accessible in managed code via ThreadHelper.Generic.Invoke.
The history of RPC calls, p. 3
 Let’s redefine RPC to mean “Re-entrant problematic call”
 RPC “re-enters” the UI thread and interrupts whatever it is doing, even irrelevant
work.
 Even highly filtered message pumps process RPC messages.
 Hangs occur when the message pump is disabled.
 Hurts responsiveness because RPC messages are processed before user input.
 Can quickly exhaust the threadpool while waiting for the UI thread, leading to
very long (80+ seconds) hangs for the user.
The history of RPC calls, p. 4
 Managed code is littered with hidden message pumps:
 C# lock keyword
 Literally everything that may result in a synchronously blocking wait because
SynchronizationContext.Wait can pump.
 Native code must explicitly request pumping (via CoWait or other Co- calls), but
these too are hidden inside unsuspecting APIs:
 IVsOutputWindowPane::OutputString (some implementations)
 Any time a message pump runs, RPC can get unrelated work in, which can hang,
corrupt data, or slow down a scenario.
Question to ponder
 Q: What's worse? Code that hangs some of the time or all of the time?
 It is preferable to consistently fail than to inconsistently succeed. Consistent
failures are much more likely to be found before shipping, and are easier to
analyze, fix, and verify.
 The 3 threading rules are designed around this high level behavioral preference.
Question to ponder
 Q: What priority should you use to get to the UI thread?
 Old Answer: Traditionally the greatest input in making this decision has been
based on finding the balance between re-entrancy and deadlocks rather than
what will provide the best user experience. The priority is set in the code that
schedules the individual task.
 Preferred answer: This should be determined by the top-level scenario, and the
majority of the working code should be oblivious to it. The priority is ‘inherited’
by the code that schedules the individual task.
The 3 VS threading rules
1. Use JoinableTaskFactory.SwitchToMainThreadAsync()
2. Use JoinableTaskFactory.Run()
3. Use JoinableTaskFactory.RunAsync()
 Flexible priority to get to the UI thread
 Never deadlocks due to WPF turning off the message pump
 Deadlocks somewhat more reliably than older methods when you break the rules
(this is a good thing!)
The 3 VS threading rules: Rule #1
Use JoinableTaskFactory.SwitchToMainThreadAsync()
 If a method is not free threaded, it must either:
 Be async and switch using SwitchToMainThreadAsync() prior to calling STA objects, OR
 Be sync and call ThreadHelper.ThrowIfNotOnUIThread();
 This is the only way you should ever need. Throw all other approaches out.
 Never use synchronous blocking methods:
 ThreadHelper.Generic.Invoke
 SynchronizationContext.Send
 RPC (implicit marshaling)
The 3 VS threading rules: Rule #1
async Task DoSomethingAsync()
{
// We’re on the caller’s thread, whatever that is.
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
// Now we’re on the UI thread! It’s safe to call STA objects.
var solution = Package.GetService(typeof(SVsSolution)) as IVsSolution;
}
void DoSomething()
{
ThreadHelper.ThrowIfNotOnUIThread();
var solution = Package.GetService(typeof(SVsSolution)) as IVsSolution;
}
The 3 VS threading rules: Rule #1
 Q: Why is it better to throw an exception from a synchronous method when
invoked from the wrong thread than to try to make it work?
 A: It’s better to throw consistently than to hang inconsistently because bugs will be
more likely caught before being checked in or shipped.
 Be cautious to not break backward compatibility. When it used to work when called
from a background thread, use Rule #2.
 Q: What if you’re already on the UI thread?
 A: SwitchToMainThreadAsync is a very cheap no-op call. Use it liberally.
The 3 VS threading rules: Rule #1
 Remember the implicit UI thread dependencies:
 In C#, casting a COM object is an STA call to IUnknown::QueryInterface
 Invoking an interface member, implemented by a native COM object
 Consider avoiding other async scheduling:
 SynchronizationContext.Post
 ThreadHelper.Generic.BeginInvoke
What about getting off the UI thread?
 Explicitly switching off the UI thread is great for:
 Disk or network access
 CPU intensive operation
 Switch away from the UI thread any way you please:
 await TaskScheduler.Default;
 await Task.Run(…);
 Caution
 Get off the UI thread only within async methods that you know only invokes code that follow
the 3 threading rules.
 Avoid Task.Factory.StartNew or Task.Factory.ContinueWith unless you specify
TaskScheduler.Default explicitly.
The 3 VS threading rules: Rule #2
Use JoinableTaskFactory.Run
 When a synchronous method needs to call async methods:
 Preferably make your sync method async.
 When that cannot be done, use JoinableTaskFactory.Run.
 Never use these on an incomplete Task:
 Task.Result
 Task.Wait()
 Bad:
 var result = GetValueAsync().Result;
 DoSomethingAsync().Wait();
The 3 VS threading rules: Rule #2
async Task DoSomethingAsync()
{
// We’re on the caller’s thread, whatever that is.
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
// Now we’re on the UI thread! It’s safe to call STA objects.
var solution = Package.GetService(typeof(SVsSolution)) as IVsSolution;
}
void DoSomething()
{
ThreadHelper.JoinableTaskFactory.Run(async delegate
{
await DoSomethingAsync();
});
}
The 3 VS threading rules: Rule #2
 Notice how we only have to implement the method once (asynchronously), and
we have our synchronous method simply call to the async one using rule #2.
 This allows async callers to call the async version of our method, avoiding threadpool
exhaustion.
 Our code is more maintainable because there is only one copy of the logic.
The 3 VS threading rules: Rule #3
Use JoinableTaskFactory.RunAsync (and Join)
 Use when an async operation might later block the UI thread.
 When it’s time to block the calling thread, use JoinableTask.Join()
 Or even better: await joinableTask;
 Never use these on an incomplete Task: (it’s worth repeating)
 Task.Result
 Task.Wait()
 Bad:
 var result = GetValueAsync().Result;
 DoSomethingAsync().Wait();
The 3 VS threading rules: Rule #3
// Simple case (but not that common, really)
private JoinableTask asyncWork;
void StartWorkAsync() {
this.asyncWork = ThreadHelper.JoinableTaskFactory.RunAsync(
async delegate {
await SomethingAsync();
});
}
void FinishNow() {
this.asyncWork.Join(); // blocks till complete, without deadlocking
}
The 3 VS threading rules: Rule #3
// More common case
private JoinableTask asyncWork;
void StartWorkAsync() {
this.asyncWork = ThreadHelper.JoinableTaskFactory.RunAsync(
async delegate {
await SomethingAsync();
});
}
void FinishNow() {
ThreadHelper.JoinableTaskFactory.Run(async delegate {
await this.asyncWork;
});
}
The 3 VS threading rules: Rule #3
 Avoid exposing JoinableTask as the return type from your public API.
 Simply return Task. It’s the caller’s responsibility to wrap with RunAsync if necessary.
 When you have your own scheduler/queue, more advanced techniques are
required!
What about IVsTask?
 IVsTask is still required if you need to implement an async COM interface.
 Don’t bother using VsTaskLibraryHelper directly to construct IVsTask. That’s too
verbose.
 But you can’t return IVsTask from a C# async method. So how do you do it?
How to return IVsTask from C# async
public IVsTask DoAsync() {
return ThreadHelper.JoinableTaskFactory.RunAsyncAsVsTask(
VsTaskRunContext.UIThreadNormalPriority, // (or lower UI thread priorities)
async cancellationToken => {
await SomethingAsync(cancellationToken);
await SomethingElseAsync();
});
}
IVsTask tips
 You can await IVsTask just fine and JoinableTaskFactory will do the right thing.
 Remember that JoinableTaskFactory.RunAsync(VsTaskRunContext) does not
automatically switch you to the UI thread!
Tip #1: Conditional switching
 If you depend on the UI thread for some code paths, verify it is available for all of
them. This makes failure more consistent and likely to be spotted.
// AVOID THIS PATTERN
async Task DoSomethingAsync() {
if (someSwitch) {
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
// Use UI thread
}
// WARNING: This code may run on either context
}
Tip #1: Conditional switching
 If you depend on the UI thread for some code paths, verify it is available for all of
them. This makes failure more consistent and likely to be spotted.
// PREFERRED pattern
async Task DoSomethingAsync() {
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
if (someSwitch) {
// conditional logic
}
// This code is consistently on the UI thread
}
Tip #2: Async constructors
 Constructors cannot be async. But static factory methods can!
class MyClass
{
private MyClass(string someValue) { … }
internal static Task<MyClass> CreateAsync()
{
string value = await DoSomethingAsync();
return new MyClass(value);
}
}
Tip #3: Avoid nesting JTF.Run
 Use JTF.Run around the entire body of your public, sync methods.
 Avoid using JTF.Run with a delegate that calls another method that itself uses
JTF.Run. These can be nested, but the complexity and overhead of multiple calls is
nice to avoid and helps you be async wherever possible.
int DoSomething () { // BAD EXAMPLE
SomeWork();
int value = JTF.Run(async () => { return await GetValueAsync(); });
return value;
}
Tip #3: Avoid nesting JTF.Run
 Use JTF.Run around the entire body of your public, sync methods.
 Avoid using JTF.Run with a delegate that calls another method that itself uses
JTF.Run. These can be nested, but the complexity and overhead of multiple calls is
nice to avoid and helps you be async wherever possible.
int DoSomething() { // BETTER EXAMPLE
return JTF.Run(async delegate {
SomeWork();
int value = await GetValueAsync()
return value;
});
}
More Tips
 Mock up the UI thread in unit tests to verify you won't deadlock.
 JoinableTaskFactory can be used in your unit tests
 Never construct a JoinableTaskContext yourself except in unit tests.
 Use the one on ThreadHelper when in devenv.exe.
 Don't exhaust the threadpool! (it's a violation of rule #1 anyway)
 Remember: MEF parts can be instantiated on any thread
Appendix
 More about the 3 threading rules
 Recipes for common VS scenarios
 Async hang debugging tips

More Related Content

What's hot

Cassandra an overview
Cassandra an overviewCassandra an overview
Cassandra an overviewPritamKathar
 
Galera Cluster - Node Recovery - Webinar slides
Galera Cluster - Node Recovery - Webinar slidesGalera Cluster - Node Recovery - Webinar slides
Galera Cluster - Node Recovery - Webinar slidesSeveralnines
 
PacNOG 23: Introduction to Crypto Jacking
PacNOG 23: Introduction to Crypto JackingPacNOG 23: Introduction to Crypto Jacking
PacNOG 23: Introduction to Crypto JackingAPNIC
 
CNIT 141: 4. Block Ciphers
CNIT 141: 4. Block CiphersCNIT 141: 4. Block Ciphers
CNIT 141: 4. Block CiphersSam Bowne
 
The Cross Site Scripting Guide
The Cross Site Scripting GuideThe Cross Site Scripting Guide
The Cross Site Scripting GuideDaisuke_Dan
 
[教材] 例外處理設計與重構實作班201309
[教材] 例外處理設計與重構實作班201309[教材] 例外處理設計與重構實作班201309
[教材] 例外處理設計與重構實作班201309teddysoft
 
SOFTCAMP SHIELDEX 詳細な紹介資料及び ​導入事例
SOFTCAMP SHIELDEX 詳細な紹介資料及び ​導入事例SOFTCAMP SHIELDEX 詳細な紹介資料及び ​導入事例
SOFTCAMP SHIELDEX 詳細な紹介資料及び ​導入事例Softcamp Co., Ltd.
 
Project Frankenstein: A multitenant, horizontally scalable Prometheus as a se...
Project Frankenstein: A multitenant, horizontally scalable Prometheus as a se...Project Frankenstein: A multitenant, horizontally scalable Prometheus as a se...
Project Frankenstein: A multitenant, horizontally scalable Prometheus as a se...Weaveworks
 
Erasure codes and storage tiers on gluster
Erasure codes and storage tiers on glusterErasure codes and storage tiers on gluster
Erasure codes and storage tiers on glusterRed_Hat_Storage
 
Os Command Injection Attack
Os Command Injection AttackOs Command Injection Attack
Os Command Injection AttackRaghav Bisht
 
CNIT 127: 4: Format string bugs
CNIT 127: 4: Format string bugsCNIT 127: 4: Format string bugs
CNIT 127: 4: Format string bugsSam Bowne
 
Druid in Spot Instances
Druid in Spot InstancesDruid in Spot Instances
Druid in Spot InstancesImply
 
Nishan e-haider
Nishan e-haiderNishan e-haider
Nishan e-haider201990
 
Kafka Security 101 and Real-World Tips
Kafka Security 101 and Real-World Tips Kafka Security 101 and Real-World Tips
Kafka Security 101 and Real-World Tips confluent
 
Cyber Security Workshop Presentation.pptx
Cyber Security Workshop Presentation.pptxCyber Security Workshop Presentation.pptx
Cyber Security Workshop Presentation.pptxYashSomalkar
 

What's hot (20)

Cross site scripting
Cross site scripting Cross site scripting
Cross site scripting
 
Buffer overflow
Buffer overflowBuffer overflow
Buffer overflow
 
mimikatz @ phdays
mimikatz @ phdaysmimikatz @ phdays
mimikatz @ phdays
 
Cassandra an overview
Cassandra an overviewCassandra an overview
Cassandra an overview
 
Galera Cluster - Node Recovery - Webinar slides
Galera Cluster - Node Recovery - Webinar slidesGalera Cluster - Node Recovery - Webinar slides
Galera Cluster - Node Recovery - Webinar slides
 
PacNOG 23: Introduction to Crypto Jacking
PacNOG 23: Introduction to Crypto JackingPacNOG 23: Introduction to Crypto Jacking
PacNOG 23: Introduction to Crypto Jacking
 
CNIT 141: 4. Block Ciphers
CNIT 141: 4. Block CiphersCNIT 141: 4. Block Ciphers
CNIT 141: 4. Block Ciphers
 
Intro to Cassandra
Intro to CassandraIntro to Cassandra
Intro to Cassandra
 
Cassandra 101
Cassandra 101Cassandra 101
Cassandra 101
 
The Cross Site Scripting Guide
The Cross Site Scripting GuideThe Cross Site Scripting Guide
The Cross Site Scripting Guide
 
[教材] 例外處理設計與重構實作班201309
[教材] 例外處理設計與重構實作班201309[教材] 例外處理設計與重構實作班201309
[教材] 例外處理設計與重構實作班201309
 
SOFTCAMP SHIELDEX 詳細な紹介資料及び ​導入事例
SOFTCAMP SHIELDEX 詳細な紹介資料及び ​導入事例SOFTCAMP SHIELDEX 詳細な紹介資料及び ​導入事例
SOFTCAMP SHIELDEX 詳細な紹介資料及び ​導入事例
 
Project Frankenstein: A multitenant, horizontally scalable Prometheus as a se...
Project Frankenstein: A multitenant, horizontally scalable Prometheus as a se...Project Frankenstein: A multitenant, horizontally scalable Prometheus as a se...
Project Frankenstein: A multitenant, horizontally scalable Prometheus as a se...
 
Erasure codes and storage tiers on gluster
Erasure codes and storage tiers on glusterErasure codes and storage tiers on gluster
Erasure codes and storage tiers on gluster
 
Os Command Injection Attack
Os Command Injection AttackOs Command Injection Attack
Os Command Injection Attack
 
CNIT 127: 4: Format string bugs
CNIT 127: 4: Format string bugsCNIT 127: 4: Format string bugs
CNIT 127: 4: Format string bugs
 
Druid in Spot Instances
Druid in Spot InstancesDruid in Spot Instances
Druid in Spot Instances
 
Nishan e-haider
Nishan e-haiderNishan e-haider
Nishan e-haider
 
Kafka Security 101 and Real-World Tips
Kafka Security 101 and Real-World Tips Kafka Security 101 and Real-World Tips
Kafka Security 101 and Real-World Tips
 
Cyber Security Workshop Presentation.pptx
Cyber Security Workshop Presentation.pptxCyber Security Workshop Presentation.pptx
Cyber Security Workshop Presentation.pptx
 

Similar to The 3 VS Threading Rules

Task parallel library presentation
Task parallel library presentationTask parallel library presentation
Task parallel library presentationahmed sayed
 
TCP Sockets Tutor maXbox starter26
TCP Sockets Tutor maXbox starter26TCP Sockets Tutor maXbox starter26
TCP Sockets Tutor maXbox starter26Max Kleiner
 
Multithreading Presentation
Multithreading PresentationMultithreading Presentation
Multithreading PresentationNeeraj Kaushik
 
Multithreading
MultithreadingMultithreading
Multithreadingbackdoor
 
Concurrency Learning From Jdk Source
Concurrency Learning From Jdk SourceConcurrency Learning From Jdk Source
Concurrency Learning From Jdk SourceKaniska Mandal
 
Async-await best practices in 10 minutes
Async-await best practices in 10 minutesAsync-await best practices in 10 minutes
Async-await best practices in 10 minutesPaulo Morgado
 
Achieving mass scale with Quasar Fibers
Achieving mass scale with Quasar FibersAchieving mass scale with Quasar Fibers
Achieving mass scale with Quasar FibersIdan Sheinberg
 
Beyond the RTOS: A Better Way to Design Real-Time Embedded Software
Beyond the RTOS: A Better Way to Design Real-Time Embedded SoftwareBeyond the RTOS: A Better Way to Design Real-Time Embedded Software
Beyond the RTOS: A Better Way to Design Real-Time Embedded SoftwareMiro Samek
 
The Pillars Of Concurrency
The Pillars Of ConcurrencyThe Pillars Of Concurrency
The Pillars Of Concurrencyaviade
 
Java Multithreading and Concurrency
Java Multithreading and ConcurrencyJava Multithreading and Concurrency
Java Multithreading and ConcurrencyRajesh Ananda Kumar
 
Spin Locks and Contention : The Art of Multiprocessor Programming : Notes
Spin Locks and Contention : The Art of Multiprocessor Programming : NotesSpin Locks and Contention : The Art of Multiprocessor Programming : Notes
Spin Locks and Contention : The Art of Multiprocessor Programming : NotesSubhajit Sahu
 
Beyond the RTOS: A Better Way to Design Real-Time Embedded Software
Beyond the RTOS: A Better Way to Design Real-Time Embedded SoftwareBeyond the RTOS: A Better Way to Design Real-Time Embedded Software
Beyond the RTOS: A Better Way to Design Real-Time Embedded SoftwareQuantum Leaps, LLC
 
692015 programming assignment 1 building a multi­threaded w
692015 programming assignment 1 building a multi­threaded w692015 programming assignment 1 building a multi­threaded w
692015 programming assignment 1 building a multi­threaded wsmile790243
 
Concurrency with java
Concurrency with javaConcurrency with java
Concurrency with javaLuis Goldster
 
Concurrency with java
Concurrency with javaConcurrency with java
Concurrency with javaHarry Potter
 
Concurrency with java
Concurrency with javaConcurrency with java
Concurrency with javaYoung Alista
 
Concurrency with java
Concurrency with javaConcurrency with java
Concurrency with javaTony Nguyen
 
Concurrency with java
Concurrency with javaConcurrency with java
Concurrency with javaFraboni Ec
 

Similar to The 3 VS Threading Rules (20)

Task parallel library presentation
Task parallel library presentationTask parallel library presentation
Task parallel library presentation
 
TCP Sockets Tutor maXbox starter26
TCP Sockets Tutor maXbox starter26TCP Sockets Tutor maXbox starter26
TCP Sockets Tutor maXbox starter26
 
Multithreading Presentation
Multithreading PresentationMultithreading Presentation
Multithreading Presentation
 
Multithreading
MultithreadingMultithreading
Multithreading
 
MultiThreading in Python
MultiThreading in PythonMultiThreading in Python
MultiThreading in Python
 
Concurrency Learning From Jdk Source
Concurrency Learning From Jdk SourceConcurrency Learning From Jdk Source
Concurrency Learning From Jdk Source
 
Async-await best practices in 10 minutes
Async-await best practices in 10 minutesAsync-await best practices in 10 minutes
Async-await best practices in 10 minutes
 
Achieving mass scale with Quasar Fibers
Achieving mass scale with Quasar FibersAchieving mass scale with Quasar Fibers
Achieving mass scale with Quasar Fibers
 
Beyond the RTOS: A Better Way to Design Real-Time Embedded Software
Beyond the RTOS: A Better Way to Design Real-Time Embedded SoftwareBeyond the RTOS: A Better Way to Design Real-Time Embedded Software
Beyond the RTOS: A Better Way to Design Real-Time Embedded Software
 
Asynchronyin net
Asynchronyin netAsynchronyin net
Asynchronyin net
 
The Pillars Of Concurrency
The Pillars Of ConcurrencyThe Pillars Of Concurrency
The Pillars Of Concurrency
 
Java Multithreading and Concurrency
Java Multithreading and ConcurrencyJava Multithreading and Concurrency
Java Multithreading and Concurrency
 
Spin Locks and Contention : The Art of Multiprocessor Programming : Notes
Spin Locks and Contention : The Art of Multiprocessor Programming : NotesSpin Locks and Contention : The Art of Multiprocessor Programming : Notes
Spin Locks and Contention : The Art of Multiprocessor Programming : Notes
 
Beyond the RTOS: A Better Way to Design Real-Time Embedded Software
Beyond the RTOS: A Better Way to Design Real-Time Embedded SoftwareBeyond the RTOS: A Better Way to Design Real-Time Embedded Software
Beyond the RTOS: A Better Way to Design Real-Time Embedded Software
 
692015 programming assignment 1 building a multi­threaded w
692015 programming assignment 1 building a multi­threaded w692015 programming assignment 1 building a multi­threaded w
692015 programming assignment 1 building a multi­threaded w
 
Concurrency with java
Concurrency with javaConcurrency with java
Concurrency with java
 
Concurrency with java
Concurrency with javaConcurrency with java
Concurrency with java
 
Concurrency with java
Concurrency with javaConcurrency with java
Concurrency with java
 
Concurrency with java
Concurrency with javaConcurrency with java
Concurrency with java
 
Concurrency with java
Concurrency with javaConcurrency with java
Concurrency with java
 

Recently uploaded

Keeping your build tool updated in a multi repository world
Keeping your build tool updated in a multi repository worldKeeping your build tool updated in a multi repository world
Keeping your build tool updated in a multi repository worldRoberto Pérez Alcolea
 
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...Bert Jan Schrijver
 
Mastering Project Planning with Microsoft Project 2016.pptx
Mastering Project Planning with Microsoft Project 2016.pptxMastering Project Planning with Microsoft Project 2016.pptx
Mastering Project Planning with Microsoft Project 2016.pptxAS Design & AST.
 
Understanding Plagiarism: Causes, Consequences and Prevention.pptx
Understanding Plagiarism: Causes, Consequences and Prevention.pptxUnderstanding Plagiarism: Causes, Consequences and Prevention.pptx
Understanding Plagiarism: Causes, Consequences and Prevention.pptxSasikiranMarri
 
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...OnePlan Solutions
 
Pros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdf
Pros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdfPros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdf
Pros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdfkalichargn70th171
 
SAM Training Session - How to use EXCEL ?
SAM Training Session - How to use EXCEL ?SAM Training Session - How to use EXCEL ?
SAM Training Session - How to use EXCEL ?Alexandre Beguel
 
Effectively Troubleshoot 9 Types of OutOfMemoryError
Effectively Troubleshoot 9 Types of OutOfMemoryErrorEffectively Troubleshoot 9 Types of OutOfMemoryError
Effectively Troubleshoot 9 Types of OutOfMemoryErrorTier1 app
 
Ronisha Informatics Private Limited Catalogue
Ronisha Informatics Private Limited CatalogueRonisha Informatics Private Limited Catalogue
Ronisha Informatics Private Limited Catalogueitservices996
 
Osi security architecture in network.pptx
Osi security architecture in network.pptxOsi security architecture in network.pptx
Osi security architecture in network.pptxVinzoCenzo
 
Zer0con 2024 final share short version.pdf
Zer0con 2024 final share short version.pdfZer0con 2024 final share short version.pdf
Zer0con 2024 final share short version.pdfmaor17
 
Effort Estimation Techniques used in Software Projects
Effort Estimation Techniques used in Software ProjectsEffort Estimation Techniques used in Software Projects
Effort Estimation Techniques used in Software ProjectsDEEPRAJ PATHAK
 
eSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration toolseSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration toolsosttopstonverter
 
What’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 UpdatesWhat’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 UpdatesVictoriaMetrics
 
The Ultimate Guide to Performance Testing in Low-Code, No-Code Environments (...
The Ultimate Guide to Performance Testing in Low-Code, No-Code Environments (...The Ultimate Guide to Performance Testing in Low-Code, No-Code Environments (...
The Ultimate Guide to Performance Testing in Low-Code, No-Code Environments (...kalichargn70th171
 
2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf
2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf
2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdfAndrey Devyatkin
 
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4jGraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4jNeo4j
 
Introduction to Firebase Workshop Slides
Introduction to Firebase Workshop SlidesIntroduction to Firebase Workshop Slides
Introduction to Firebase Workshop Slidesvaideheekore1
 
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full RecordingOpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full RecordingShane Coughlan
 
Advantages of Cargo Cloud Solutions.pptx
Advantages of Cargo Cloud Solutions.pptxAdvantages of Cargo Cloud Solutions.pptx
Advantages of Cargo Cloud Solutions.pptxRTS corp
 

Recently uploaded (20)

Keeping your build tool updated in a multi repository world
Keeping your build tool updated in a multi repository worldKeeping your build tool updated in a multi repository world
Keeping your build tool updated in a multi repository world
 
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
 
Mastering Project Planning with Microsoft Project 2016.pptx
Mastering Project Planning with Microsoft Project 2016.pptxMastering Project Planning with Microsoft Project 2016.pptx
Mastering Project Planning with Microsoft Project 2016.pptx
 
Understanding Plagiarism: Causes, Consequences and Prevention.pptx
Understanding Plagiarism: Causes, Consequences and Prevention.pptxUnderstanding Plagiarism: Causes, Consequences and Prevention.pptx
Understanding Plagiarism: Causes, Consequences and Prevention.pptx
 
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
 
Pros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdf
Pros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdfPros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdf
Pros and Cons of Selenium In Automation Testing_ A Comprehensive Assessment.pdf
 
SAM Training Session - How to use EXCEL ?
SAM Training Session - How to use EXCEL ?SAM Training Session - How to use EXCEL ?
SAM Training Session - How to use EXCEL ?
 
Effectively Troubleshoot 9 Types of OutOfMemoryError
Effectively Troubleshoot 9 Types of OutOfMemoryErrorEffectively Troubleshoot 9 Types of OutOfMemoryError
Effectively Troubleshoot 9 Types of OutOfMemoryError
 
Ronisha Informatics Private Limited Catalogue
Ronisha Informatics Private Limited CatalogueRonisha Informatics Private Limited Catalogue
Ronisha Informatics Private Limited Catalogue
 
Osi security architecture in network.pptx
Osi security architecture in network.pptxOsi security architecture in network.pptx
Osi security architecture in network.pptx
 
Zer0con 2024 final share short version.pdf
Zer0con 2024 final share short version.pdfZer0con 2024 final share short version.pdf
Zer0con 2024 final share short version.pdf
 
Effort Estimation Techniques used in Software Projects
Effort Estimation Techniques used in Software ProjectsEffort Estimation Techniques used in Software Projects
Effort Estimation Techniques used in Software Projects
 
eSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration toolseSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration tools
 
What’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 UpdatesWhat’s New in VictoriaMetrics: Q1 2024 Updates
What’s New in VictoriaMetrics: Q1 2024 Updates
 
The Ultimate Guide to Performance Testing in Low-Code, No-Code Environments (...
The Ultimate Guide to Performance Testing in Low-Code, No-Code Environments (...The Ultimate Guide to Performance Testing in Low-Code, No-Code Environments (...
The Ultimate Guide to Performance Testing in Low-Code, No-Code Environments (...
 
2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf
2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf
2024-04-09 - From Complexity to Clarity - AWS Summit AMS.pdf
 
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4jGraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
 
Introduction to Firebase Workshop Slides
Introduction to Firebase Workshop SlidesIntroduction to Firebase Workshop Slides
Introduction to Firebase Workshop Slides
 
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full RecordingOpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
 
Advantages of Cargo Cloud Solutions.pptx
Advantages of Cargo Cloud Solutions.pptxAdvantages of Cargo Cloud Solutions.pptx
Advantages of Cargo Cloud Solutions.pptx
 

The 3 VS Threading Rules

  • 1. The 3 VS Threading Rules WATCH THE VIDEO OF THE ORIGINAL PRESENTATION
  • 2. The history of RPC calls, p. 1  RPC = Remote Procedure Call  It blocks the calling thread, sends a high priority message to the UI thread and only unblocks the calling thread after the UI thread processes the message.  Allows the caller to remain unaware of threading requirements of the COM object it is invoking.  Is often used in scenarios where you have code that kicks off background thread work and blocks the UI thread on its completion, since RPC can penetrate the blocking wait so that the background thread work can use the UI thread as part of its work.
  • 3. The history of RPC calls, p. 2  Implicitly used whenever native or managed code calls a COM object implemented in native code (roughly).  Also explicitly accessible in managed code via ThreadHelper.Generic.Invoke.
  • 4. The history of RPC calls, p. 3  Let’s redefine RPC to mean “Re-entrant problematic call”  RPC “re-enters” the UI thread and interrupts whatever it is doing, even irrelevant work.  Even highly filtered message pumps process RPC messages.  Hangs occur when the message pump is disabled.  Hurts responsiveness because RPC messages are processed before user input.  Can quickly exhaust the threadpool while waiting for the UI thread, leading to very long (80+ seconds) hangs for the user.
  • 5. The history of RPC calls, p. 4  Managed code is littered with hidden message pumps:  C# lock keyword  Literally everything that may result in a synchronously blocking wait because SynchronizationContext.Wait can pump.  Native code must explicitly request pumping (via CoWait or other Co- calls), but these too are hidden inside unsuspecting APIs:  IVsOutputWindowPane::OutputString (some implementations)  Any time a message pump runs, RPC can get unrelated work in, which can hang, corrupt data, or slow down a scenario.
  • 6. Question to ponder  Q: What's worse? Code that hangs some of the time or all of the time?  It is preferable to consistently fail than to inconsistently succeed. Consistent failures are much more likely to be found before shipping, and are easier to analyze, fix, and verify.  The 3 threading rules are designed around this high level behavioral preference.
  • 7. Question to ponder  Q: What priority should you use to get to the UI thread?  Old Answer: Traditionally the greatest input in making this decision has been based on finding the balance between re-entrancy and deadlocks rather than what will provide the best user experience. The priority is set in the code that schedules the individual task.  Preferred answer: This should be determined by the top-level scenario, and the majority of the working code should be oblivious to it. The priority is ‘inherited’ by the code that schedules the individual task.
  • 8. The 3 VS threading rules 1. Use JoinableTaskFactory.SwitchToMainThreadAsync() 2. Use JoinableTaskFactory.Run() 3. Use JoinableTaskFactory.RunAsync()  Flexible priority to get to the UI thread  Never deadlocks due to WPF turning off the message pump  Deadlocks somewhat more reliably than older methods when you break the rules (this is a good thing!)
  • 9. The 3 VS threading rules: Rule #1 Use JoinableTaskFactory.SwitchToMainThreadAsync()  If a method is not free threaded, it must either:  Be async and switch using SwitchToMainThreadAsync() prior to calling STA objects, OR  Be sync and call ThreadHelper.ThrowIfNotOnUIThread();  This is the only way you should ever need. Throw all other approaches out.  Never use synchronous blocking methods:  ThreadHelper.Generic.Invoke  SynchronizationContext.Send  RPC (implicit marshaling)
  • 10. The 3 VS threading rules: Rule #1 async Task DoSomethingAsync() { // We’re on the caller’s thread, whatever that is. await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); // Now we’re on the UI thread! It’s safe to call STA objects. var solution = Package.GetService(typeof(SVsSolution)) as IVsSolution; } void DoSomething() { ThreadHelper.ThrowIfNotOnUIThread(); var solution = Package.GetService(typeof(SVsSolution)) as IVsSolution; }
  • 11. The 3 VS threading rules: Rule #1  Q: Why is it better to throw an exception from a synchronous method when invoked from the wrong thread than to try to make it work?  A: It’s better to throw consistently than to hang inconsistently because bugs will be more likely caught before being checked in or shipped.  Be cautious to not break backward compatibility. When it used to work when called from a background thread, use Rule #2.  Q: What if you’re already on the UI thread?  A: SwitchToMainThreadAsync is a very cheap no-op call. Use it liberally.
  • 12. The 3 VS threading rules: Rule #1  Remember the implicit UI thread dependencies:  In C#, casting a COM object is an STA call to IUnknown::QueryInterface  Invoking an interface member, implemented by a native COM object  Consider avoiding other async scheduling:  SynchronizationContext.Post  ThreadHelper.Generic.BeginInvoke
  • 13. What about getting off the UI thread?  Explicitly switching off the UI thread is great for:  Disk or network access  CPU intensive operation  Switch away from the UI thread any way you please:  await TaskScheduler.Default;  await Task.Run(…);  Caution  Get off the UI thread only within async methods that you know only invokes code that follow the 3 threading rules.  Avoid Task.Factory.StartNew or Task.Factory.ContinueWith unless you specify TaskScheduler.Default explicitly.
  • 14. The 3 VS threading rules: Rule #2 Use JoinableTaskFactory.Run  When a synchronous method needs to call async methods:  Preferably make your sync method async.  When that cannot be done, use JoinableTaskFactory.Run.  Never use these on an incomplete Task:  Task.Result  Task.Wait()  Bad:  var result = GetValueAsync().Result;  DoSomethingAsync().Wait();
  • 15. The 3 VS threading rules: Rule #2 async Task DoSomethingAsync() { // We’re on the caller’s thread, whatever that is. await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); // Now we’re on the UI thread! It’s safe to call STA objects. var solution = Package.GetService(typeof(SVsSolution)) as IVsSolution; } void DoSomething() { ThreadHelper.JoinableTaskFactory.Run(async delegate { await DoSomethingAsync(); }); }
  • 16. The 3 VS threading rules: Rule #2  Notice how we only have to implement the method once (asynchronously), and we have our synchronous method simply call to the async one using rule #2.  This allows async callers to call the async version of our method, avoiding threadpool exhaustion.  Our code is more maintainable because there is only one copy of the logic.
  • 17. The 3 VS threading rules: Rule #3 Use JoinableTaskFactory.RunAsync (and Join)  Use when an async operation might later block the UI thread.  When it’s time to block the calling thread, use JoinableTask.Join()  Or even better: await joinableTask;  Never use these on an incomplete Task: (it’s worth repeating)  Task.Result  Task.Wait()  Bad:  var result = GetValueAsync().Result;  DoSomethingAsync().Wait();
  • 18. The 3 VS threading rules: Rule #3 // Simple case (but not that common, really) private JoinableTask asyncWork; void StartWorkAsync() { this.asyncWork = ThreadHelper.JoinableTaskFactory.RunAsync( async delegate { await SomethingAsync(); }); } void FinishNow() { this.asyncWork.Join(); // blocks till complete, without deadlocking }
  • 19. The 3 VS threading rules: Rule #3 // More common case private JoinableTask asyncWork; void StartWorkAsync() { this.asyncWork = ThreadHelper.JoinableTaskFactory.RunAsync( async delegate { await SomethingAsync(); }); } void FinishNow() { ThreadHelper.JoinableTaskFactory.Run(async delegate { await this.asyncWork; }); }
  • 20. The 3 VS threading rules: Rule #3  Avoid exposing JoinableTask as the return type from your public API.  Simply return Task. It’s the caller’s responsibility to wrap with RunAsync if necessary.  When you have your own scheduler/queue, more advanced techniques are required!
  • 21. What about IVsTask?  IVsTask is still required if you need to implement an async COM interface.  Don’t bother using VsTaskLibraryHelper directly to construct IVsTask. That’s too verbose.  But you can’t return IVsTask from a C# async method. So how do you do it?
  • 22. How to return IVsTask from C# async public IVsTask DoAsync() { return ThreadHelper.JoinableTaskFactory.RunAsyncAsVsTask( VsTaskRunContext.UIThreadNormalPriority, // (or lower UI thread priorities) async cancellationToken => { await SomethingAsync(cancellationToken); await SomethingElseAsync(); }); }
  • 23. IVsTask tips  You can await IVsTask just fine and JoinableTaskFactory will do the right thing.  Remember that JoinableTaskFactory.RunAsync(VsTaskRunContext) does not automatically switch you to the UI thread!
  • 24. Tip #1: Conditional switching  If you depend on the UI thread for some code paths, verify it is available for all of them. This makes failure more consistent and likely to be spotted. // AVOID THIS PATTERN async Task DoSomethingAsync() { if (someSwitch) { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); // Use UI thread } // WARNING: This code may run on either context }
  • 25. Tip #1: Conditional switching  If you depend on the UI thread for some code paths, verify it is available for all of them. This makes failure more consistent and likely to be spotted. // PREFERRED pattern async Task DoSomethingAsync() { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); if (someSwitch) { // conditional logic } // This code is consistently on the UI thread }
  • 26. Tip #2: Async constructors  Constructors cannot be async. But static factory methods can! class MyClass { private MyClass(string someValue) { … } internal static Task<MyClass> CreateAsync() { string value = await DoSomethingAsync(); return new MyClass(value); } }
  • 27. Tip #3: Avoid nesting JTF.Run  Use JTF.Run around the entire body of your public, sync methods.  Avoid using JTF.Run with a delegate that calls another method that itself uses JTF.Run. These can be nested, but the complexity and overhead of multiple calls is nice to avoid and helps you be async wherever possible. int DoSomething () { // BAD EXAMPLE SomeWork(); int value = JTF.Run(async () => { return await GetValueAsync(); }); return value; }
  • 28. Tip #3: Avoid nesting JTF.Run  Use JTF.Run around the entire body of your public, sync methods.  Avoid using JTF.Run with a delegate that calls another method that itself uses JTF.Run. These can be nested, but the complexity and overhead of multiple calls is nice to avoid and helps you be async wherever possible. int DoSomething() { // BETTER EXAMPLE return JTF.Run(async delegate { SomeWork(); int value = await GetValueAsync() return value; }); }
  • 29. More Tips  Mock up the UI thread in unit tests to verify you won't deadlock.  JoinableTaskFactory can be used in your unit tests  Never construct a JoinableTaskContext yourself except in unit tests.  Use the one on ThreadHelper when in devenv.exe.  Don't exhaust the threadpool! (it's a violation of rule #1 anyway)  Remember: MEF parts can be instantiated on any thread
  • 30. Appendix  More about the 3 threading rules  Recipes for common VS scenarios  Async hang debugging tips

Editor's Notes

  1. This makes RPC the “sharpest knife in the drawer” to get to the UI thread, but also leads to data corruption and other kinds of hangs. WPF disables the message pump during its “measure/layout” phase and then calls arbitrary VS party code that doesn’t expect this resulting in hangs.
  2. You can await as often as you like in an async method. After each await, your code will resume in the same context it was in when it yielded. No need to use Task.ConfigureAwait(false);
  3. The JoinableTaskFactory can infer all sorts of subtle dependencies for you to avoid deadlocks. But it isn’t a real oracle, and once you set up your own work queues or schedulers, you have to help it out. That’s material for another meeting, if there is demand for it.
  4. Not only is this pattern problematic for the code below the if block, it can hide threading rule violations in this or surrounding code because you may only be testing in cases that skip the UI thread dependency.
  5. Not only is this pattern problematic for the code below the if block, it can hide threading rule violations in this or surrounding code because you may only be testing in cases that skip the UI thread dependency.
  6. Avoid constructors that have thread affinity! Do the work in async factory methods.
  7. Of course if the method is not public, the best solution is usually to make the method itself async and do away with JTF.Run altogether!