jamesaskJuly 29, 20120

  • 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?的更多相关文章

  1. Threading in C#

    http://www.albahari.com/threading/ PART 1: GETTING STARTED Introduction and Concepts C# supports par ...

  2. 不完全翻译:Threading in C#-Getting Started

    Introduction(引入,介绍) and Concepts(概念) 原文地址:http://www.albahari.com/threading/ 注:水平有限不能全文翻译,备注了个别字段和短句 ...

  3. 2018.8.14-C#复习笔记总

    using System; using System.Collections.Generic; //using System.Linq; using System.Text; using System ...

  4. C#多线程同步事件及等待句柄AutoResetEvent 和 ManualResetEvent

    最近捣鼓了一下多线程的同步问题,发现其实C#关于多线程同步事件处理还是很灵活,这里主要写一下,自己测试的一些代码,涉及到了AutoResetEvent 和 ManualResetEvent,当然还有也 ...

  5. C#线程同步的几种方法

    一.volatile关键字 volatile是最简单的一种同步方法,当然简单是要付出代价的.它只能在变量一级做同步,volatile的含义就是告诉处理器, 不要将我放入工作内存, 请直接在主存操作我. ...

  6. [C#]线程处理

    线程处理用于使程序能够执行并发处理,同时执行多个操作.C#中有三种线程的使用方法,BackgroundWorker组件.线程池.自己创建使用线程,接下来分别介绍如何使用. 1.使用Background ...

  7. C#线程同步方法汇总

    我们在编程的时候,有时会使用多线程来解决问题,比如你的程序需要在 后台处理一大堆数据,但还要使用户界面处于可操作状态:或者你的程序需要访问一些外部资源如数据库或网络文件等.这些情况你都可以创建一个子线 ...

  8. 归纳一下:C#线程同步的几种方法

    转自原文 归纳一下:C#线程同步的几种方法 我们在编程的时候,有时会使用多线程来解决问题,比如你的程序需要在后台处理一大堆数据,但还要使用户界面处于可操作状态:或者你的程序需要访问一些外部资源如数据库 ...

  9. Waiting on Groups of Queued Tasks

    https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingG ...

随机推荐

  1. 安全测试===appscan扫描工具介绍

    IBM AppScan该产品是一个领先的 Web 应用安全测试工具,曾以 Watchfire AppScan 的名称享誉业界.Rational AppScan 可自动化 Web 应用的安全漏洞评估工作 ...

  2. PXC 避免加入集群时发生SST

    环境 现有集群节点: 192.168.99.210:3101 新加入节点: 192.168.99.211:3101 通过xtrabackup备份还原实例,并通过同步方式追数据: 已有节点情况: roo ...

  3. VI编辑,backspace无法删除解决方法

    系统ubuntu 1,sudo apt-get install vim  安装vim 2, sudo vi  /etc/vim/vimrc.tiny 修改 set compatible为set noc ...

  4. apache加入chkconfig

    #First Step: cp /usr/local/apache2/bin/apachectl /etc/init.d/httpd #Second Step: vim /etc/init.d/htt ...

  5. 坐标转换——GCJ-02

    WGS84(World Geodetic System 1984),是为GPS 全球定位系统 使用而建立的坐标系统GCJ-02,我国在WGS84的基础上加密得到BD-09,百度坐标在GCJ-02基础上 ...

  6. leetcode 之Linked List Cycle(24)

    两个思路,一是用哈希表记录每个结点是还被访问过:二是定义两个快.慢指针,如果存在环的话,两个指针必定会在某位结点相遇. bool linkListNode(ListNode *head) { List ...

  7. Tomcat手动指定jdk路径

    Windows系统: 修改bin下的setclasspath.bat,在开头处添加: rem set specific jdkset JAVA_HOME=%CATALINA_HOME%\jdk1.8. ...

  8. GT-----FAQ整理

    1.pss0,pss1,这里的序号0和1是什么意思?      说明选的目标调试 App 有至少 2 个进程,先启动的那个进程的 pss 值会被加后缀 0,后启动那个会被加后 缀 1.所有参数前面的“ ...

  9. spring-web涉及jar包说明

    <!-- spring-context, spring-aop, spring-beans, spring-core, spring-expression --> <dependen ...

  10. 封装ajax支持get、post

    为什么要封装ajax,因为…… for(var i=0;i<20;i++){ $.ajax(……) } 的时候,整个页面都卡死了,于是,我开始找答案. 后来,找到了,就是jquery的ajax属 ...