Do waiting or suspended tasks tie up a worker thread?
- I had a discussion the other day with someone about worker threads and their relation to tasks. I thought a quick demo might be worthwhile. When we have tasks that are waiting on a resource (whether it be a timer or a resource like a lock) we are tying up a worker thread. A worker thread is assigned to a task for the duration of that task. For most queries, this means for the duration of the user’s request or query. Let’s look at two examples below.
We could verify that the worker thread is tied up by verifying the state the worker thread is in and that it is assigned to our tasks through the following two DMVs:
select * from sys.dm_os_workers
select * from sys.dm_os_tasks
If we start a 5 minute delay to tie up a worker thread using session 55 as follows:
waitfor delay '00:05:00'
Then we can use the following to verify our worker thread is assigned to our task and suspended while it waits on the timer:
select
w.worker_address,
w.state,
w.task_address,
t.session_id
from sys.dm_os_tasks t
inner join sys.dm_os_workers w
on t.worker_address = w.worker_address
where t.session_id = 55
![]()
However, we can also get the worker’s OS thread ID and view the call stack to see that it is not merely waiting for work to do – but is tied up waiting to complete. For the above worker thread running on SPID 55, we can run the following to get the os thread id:
select os_thread_id from sys.dm_os_tasks t
inner join sys.dm_os_workers w
on t.worker_address = w.worker_address
inner join sys.dm_os_threads o
on o.worker_address = w.worker_address
where t.session_id = 55
this gives us:
![]()
Now we can get the stack trace of os thread 8376. And it is:
kernel32.dll!SignalObjectAndWait+0x110
sqlservr.exe!SOS_Scheduler::Switch+0x181
sqlservr.exe!SOS_Scheduler::SuspendNonPreemptive+0xca
sqlservr.exe!SOS_Scheduler::Suspend+0x2d
sqlservr.exe!SOS_Task::Sleep+0xec
sqlservr.exe!CStmtWait::XretExecute+0x38b
sqlservr.exe!CMsqlExecContext::ExecuteStmts<1,1>+0x375
sqlservr.exe!CMsqlExecContext::FExecute+0x97e
sqlservr.exe!CSQLSource::Execute+0x7b5
sqlservr.exe!process_request+0x64b
sqlservr.exe!process_commands+0x4e5
sqlservr.exe!SOS_Task::Param::Execute+0x12a
sqlservr.exe!SOS_Scheduler::RunTask+0x96
sqlservr.exe!SOS_Scheduler::ProcessTasks+0x128
sqlservr.exe!SchedulerManager::WorkerEntryPoint+0x2d2
sqlservr.exe!SystemThread::RunWorker+0xcc
sqlservr.exe!SystemThreadDispatcher::ProcessWorker+0x2db
sqlservr.exe!SchedulerManager::ThreadEntryPoint+0x173
MSVCR80.dll!_callthreadstartex+0x17
MSVCR80.dll!_threadstartex+0x84
kernel32.dll!BaseThreadInitThunk+0xd
ntdll.dll!RtlUserThreadStart+0x1d
From the highlighted sections in the stack trace above, we can see this is a worker thread that is processing commands (our WAITFOR DELAY statement). It has entered a sleep as a result of our WAITFOR DELAY call and SQL Server OS has switched it off the scheduler since there isn’t anything it can do for 5 minutes. Once the timer expires, the thread will be signaled and can be placed back into the RUNNABLE queue in case there is any more work for it to do.
So our thread is in effect tied up and can’t do any work for 5 minutes. Extensive use of WAITFOR could be a good way to choke the system. What about normal resources? What if we are waiting to obtain a shared lock (LCK_M_S)? Same story… Let’s look…
We can create a simple table and do an insert without closing the transaction to hold the locks…
create table Customers
(
ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
FIRSTNAME NVARCHAR(30),
LASTNAME NVARCHAR(30)
)
ON [PRIMARY]
GO BEGIN TRAN
INSERT INTO CUSTOMERS (FIRSTNAME, LASTNAME) VALUES ('John', 'Doe')
INSERT INTO CUSTOMERS (FIRSTNAME, LASTNAME) VALUES ('Jane', 'Doe')
INSERT INTO CUSTOMERS (FIRSTNAME, LASTNAME) VALUES ('George', 'Doe')
Now from another session (session 56), we can try to read that table – which will block hopelessly…
select * from Customers
Once again, we use the query from above to get our OS Thread ID:
select os_thread_id from sys.dm_os_tasks t
inner join sys.dm_os_workers w
on t.worker_address = w.worker_address
inner join sys.dm_os_threads o
on o.worker_address = w.worker_address
where t.session_id = 56
![]()
And now we are ready to get the stack for this thread:
kernel32.dll!SignalObjectAndWait+0x110
sqlservr.exe!SOS_Scheduler::Switch+0x181
sqlservr.exe!SOS_Scheduler::SuspendNonPreemptive+0xca
sqlservr.exe!SOS_Scheduler::Suspend+0x2d
sqlservr.exe!EventInternal<Spinlock<153,1,0> >::Wait+0x1a8
sqlservr.exe!LockOwner::Sleep+0x1f7
sqlservr.exe!lck_lockInternal+0xd7a
sqlservr.exe!GetLock+0x1eb
sqlservr.exe!BTreeRow::AcquireLock+0x1f9
sqlservr.exe!IndexRowScanner::AcquireNextRowLock+0x1e1
sqlservr.exe!IndexDataSetSession::GetNextRowValuesInternal+0x1397
sqlservr.exe!RowsetNewSS::FetchNextRow+0x159
sqlservr.exe!CQScanRowsetNew::GetRowWithPrefetch+0x47
sqlservr.exe!CQScanTableScanNew::GetRowDirectSelect+0x29
sqlservr.exe!CQScanTableScanNew::GetRow+0x71
sqlservr.exe!CQueryScan::GetRow+0x69
sqlservr.exe!CXStmtQuery::ErsqExecuteQuery+0x602
sqlservr.exe!CXStmtSelect::XretExecute+0x2dd
sqlservr.exe!CMsqlExecContext::ExecuteStmts<1,1>+0x375
sqlservr.exe!CMsqlExecContext::FExecute+0x97e
sqlservr.exe!CSQLSource::Execute+0x7b5
sqlservr.exe!process_request+0x64b
sqlservr.exe!process_commands+0x4e5
sqlservr.exe!SOS_Task::Param::Execute+0x12a
sqlservr.exe!SOS_Scheduler::RunTask+0x96
sqlservr.exe!SOS_Scheduler::ProcessTasks+0x128
sqlservr.exe!SchedulerManager::WorkerEntryPoint+0x2d2
sqlservr.exe!SystemThread::RunWorker+0xcc
sqlservr.exe!SystemThreadDispatcher::ProcessWorker+0x2db
sqlservr.exe!SchedulerManager::ThreadEntryPoint+0x173
MSVCR80.dll!_callthreadstartex+0x17
MSVCR80.dll!_threadstartex+0x84
kernel32.dll!BaseThreadInitThunk+0xd
ntdll.dll!RtlUserThreadStart+0x1d
Again, our worker thread processes our command (the SELECT query) and goes into a sleep. Notice this is just the name of the method from the “LockOwner” class – not the same sleep as above that is bound to a timer. The SOS scheduler switches us off and we wait to be signaled that our lock is available. This thread is “tied up” – waiting to continue.
These are the reasons that massive blocking cases can eventually lead to worker thread depletion – and waits on THREADPOOL.
-Jay
Do waiting or suspended tasks tie up a worker thread?的更多相关文章
- Threading in C#
http://www.albahari.com/threading/ PART 1: GETTING STARTED Introduction and Concepts C# supports par ...
- 不完全翻译:Threading in C#-Getting Started
Introduction(引入,介绍) and Concepts(概念) 原文地址:http://www.albahari.com/threading/ 注:水平有限不能全文翻译,备注了个别字段和短句 ...
- 2018.8.14-C#复习笔记总
using System; using System.Collections.Generic; //using System.Linq; using System.Text; using System ...
- C#多线程同步事件及等待句柄AutoResetEvent 和 ManualResetEvent
最近捣鼓了一下多线程的同步问题,发现其实C#关于多线程同步事件处理还是很灵活,这里主要写一下,自己测试的一些代码,涉及到了AutoResetEvent 和 ManualResetEvent,当然还有也 ...
- C#线程同步的几种方法
一.volatile关键字 volatile是最简单的一种同步方法,当然简单是要付出代价的.它只能在变量一级做同步,volatile的含义就是告诉处理器, 不要将我放入工作内存, 请直接在主存操作我. ...
- [C#]线程处理
线程处理用于使程序能够执行并发处理,同时执行多个操作.C#中有三种线程的使用方法,BackgroundWorker组件.线程池.自己创建使用线程,接下来分别介绍如何使用. 1.使用Background ...
- C#线程同步方法汇总
我们在编程的时候,有时会使用多线程来解决问题,比如你的程序需要在 后台处理一大堆数据,但还要使用户界面处于可操作状态:或者你的程序需要访问一些外部资源如数据库或网络文件等.这些情况你都可以创建一个子线 ...
- 归纳一下:C#线程同步的几种方法
转自原文 归纳一下:C#线程同步的几种方法 我们在编程的时候,有时会使用多线程来解决问题,比如你的程序需要在后台处理一大堆数据,但还要使用户界面处于可操作状态:或者你的程序需要访问一些外部资源如数据库 ...
- Waiting on Groups of Queued Tasks
https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingG ...
随机推荐
- C#使用Linq To XML读取XML,Linq生成XML,Linq创建带属性或带节点XML
using System; using System.Linq; using System.Xml.Linq; namespace Sample2 { class Program { static v ...
- MVC 从控制器将数据对象赋值给前端JS对象
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport&quo ...
- 图论-强连通分量-Tarjan算法
有关概念: 如果图中两个结点可以相互通达,则称两个结点强连通. 如果有向图G的每两个结点都强连通,称G是一个强连通图. 有向图的极大强连通子图(没有被其他强连通子图包含),称为强连通分量.(这个定义在 ...
- Oracle简述
Oracle是甲骨文公司推出的一款大型数据库管理系统.甲骨文公司成立于1977年,总部位于美国加利福尼亚州的红木滩.1989年,Oracle正式进入中国市场:2013年,甲骨文超越 IBM ,成为继 ...
- JWT认证不通过导致不能访问视图的解决方案
在做商城项目的购物车模块时,发现了一个问题. 需求:当用户登录时,添加商品到购物车的数据保存在redis.当用户未登录时,添加商品到购物车的数据保存在cookies.两个功能都写在一个视图里面.以JW ...
- bzoj 1449 费用流
思路:先把没有进行的场次规定双方都为负,对于x胜y负 变为x + 1胜 y - 1 负所需要的代价为 2 * C[ i ] * x - 2 * D[ i ] * y + C[ i ] + D[ i ...
- 【剑指offer】面试题 28. 对称的二叉树
面试题 28. 对称的二叉树 题目描述 题目:请实现一个函数,用来判断一颗二叉树是不是对称的.注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的. 解答过程 给定一个二叉树,检查它是否是镜像 ...
- STL模板整理 Binary search(二分查找)
前言: 之前做题二分都是手动二分造轮子,用起来总是差强人意,后来看到STL才发现前辈们早就把轮子造好了,不得不说比自己手动实现好多了. 常用操作 1.头文件 #include <algorith ...
- 0821Servlet基础
什么是servlet jsp页面的前身是servlet, 但是servlet和jsp是两个不同概念 servlet是运行在服务器端的一段程序, 是可以直接运行一段java后台代码 ...
- es6 Object的几个新方法
扩展对象 Object.preventExtensions Object.isExtensible 密封对象 Object.seal Object.isSealed 冻结对象 Object.freez ...