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. redis线程安全性

    总体来说快速的原因如下: 1)绝大部分请求是纯粹的内存操作(非常快速) 2)采用单线程,避免了不必要的上下文切换和竞争条件 3)非阻塞IO 内部实现采用epoll,采用了epoll+自己实现的简单的事 ...

  2. 运输层和TCP/IP协议

    0. 基本要点 运输层是为相互通信的应用进程提供逻辑通信. 端口和套接字的意义 什么是无连接UDP 什么是面向连接的TCP 在不可靠的网络上实现可靠传输的工作原理,停止等待协议和ARQ协议 TCP的滑 ...

  3. nginx学习时使用EditPuls编辑conf.xml

    一.Nginx简介:是一个使用c语言开发的高性能的http服务器及反向代理服务器 二.由于在linux环境中使用vim修改配置文件相对困难.为此,我们可以借助EditPlus将虚拟机上面的目录引用到E ...

  4. python--tesseract

    tesseract的介绍 我们爬虫会受到阻碍,其中一个便是我们在模拟登陆或者请求一些数据的时候,出现的图形验证码,因此我们需要一种能叫图形验证码识别成文本的技术.将图片翻译成文字一般称为光学文字识别( ...

  5. 深度学习方法:受限玻尔兹曼机RBM(四)对比散度contrastive divergence,CD

    欢迎转载,转载请注明:本文出自Bin的专栏blog.csdn.net/xbinworld. 技术交流QQ群:433250724,欢迎对算法.技术.应用感兴趣的同学加入 上篇讲到,如果用Gibbs Sa ...

  6. Markdown语法简编

    [笔者按]Markdown语法的最大的特点在于原文语法少而简,内容纯文本化,且生成的版式简洁优雅.本文参考了一些网上的参考文字,经自行精简整理. 区块元素 段落和换行,标题,引用,列表,代码块,分隔线 ...

  7. YumRepo Error: All mirror URLs are not using

    yum 安装软件出错,最后发现是网络被拦截导致.

  8. nigin配置安全:三个案例看Nginx配置安全(转)

    转:https://www.leavesongs.com/PENETRATION/nginx-insecure-configuration.html 三个案例看Nginx配置安全 PHITHON  之 ...

  9. (6) go 流程控制

    一. if else (1)如果只有一条语句,大括号不能省略 (2)右括号 和 else 在一行 (3)支持 if 时可以定义变量 (4)if 的风格尽量不要加括号,用空格代替 (5)多分支 二.sw ...

  10. 洛谷P2874 [USACO07FEB]新牛棚Building A New Barn [贪心]

    题目传送门 题目描述 After scrimping and saving for years, Farmer John has decided to build a new barn. He wan ...