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 ...
随机推荐
- jQuery Validate插件 验证实例
官网地址:http://bassistance.de/jquery-plugins/jquery-plugin-validation Validate手册: http://www.cnblogs.co ...
- windows7 能连接移动硬盘 无法显示盘符
右键点我的电脑,管理里,点磁盘管理,看盘认到没,有时候认到了但是没给盘符,需要自己手动给一个
- ADO POST时出现“无法为更新定位行,一些值可能已在最后一次读取后已更改”问题的解决方法
原因有这样几种: 1.在数据库设计时,为某些字段设置了默认值,在修改进行提交以后,数据库会自动修改对应字段的所有行的默认值,从而导致了数据库与数据集中数据的不一致,使ADOQuery无法对数据集进行定 ...
- 【hihocoder】sam1-基本概念
这题有毒…… 原本只是想复习下sam,于是写…… 后来发现自己傻了不知道怎么维护endpos…… 一气之下直接kmp拉倒,mdzz UPD:现在我好像会维护endpos了…… #include< ...
- 图论-强连通分量-Tarjan算法
有关概念: 如果图中两个结点可以相互通达,则称两个结点强连通. 如果有向图G的每两个结点都强连通,称G是一个强连通图. 有向图的极大强连通子图(没有被其他强连通子图包含),称为强连通分量.(这个定义在 ...
- C11 标准特性研究
前言 - 需要点开头 C11标准是C语言标准的第三版(2011年由ISO/IEC发布),前一个标准版本是C99标准. 相比C99,C11有哪些变化呢!!所有的测试全部基于能够和标准贴合的特性平台. 但 ...
- java 内部类和静态内部类的区别
private class InnerClass { // 只有在静态内部类中才能够声明或定义静态成员 // private static String tt = &quo ...
- 深度学习方法:受限玻尔兹曼机RBM(三)模型求解,Gibbs sampling
欢迎转载,转载请注明:本文出自Bin的专栏blog.csdn.net/xbinworld. 技术交流QQ群:433250724,欢迎对算法.技术.应用感兴趣的同学加入. 接下来重点讲一下RBM模型求解 ...
- python中的is, ==与对象的相等判断
在java中,对于两个对象啊a,b,若a==b表示,a和b不仅值相等,而且指向同一内存位置,若仅仅比较值相等,应该用equals.而在python中对应上述两者的是‘is’ 和‘==’. (1) py ...
- WP集成七牛云存储(原创)
借助:七牛镜像存储 WordPress 插件 https://wordpress.org/plugins/wpjam-qiniu/ 安装本插件1.4.5及以上版本,请先安装并激活WPJAM BASIC ...