我读过几篇文章和帖子是说lock(this),lock(typeof(MyType)),lock("a string")都是不好的做法,因为另一个线程可以锁定相同的密钥和导致死锁.为了理解这个问题,我试图创建一些示例代码来说明死锁,但一直无法解决这个问题.
有人可以编写一个简洁的代码来说明这个经典问题吗?请保持简短,我只能在较小的块中消化代码.
编辑: 我认为lassevk总结得很好; 真正的问题是你失去了对锁的控制.一旦发生这种情况,您无法控制锁被调用的顺序,并且您允许潜在的死锁情况.
lock(this),lock(typeof(MyType))等所有的情况下,你选择了一个锁是无法控制的情况.
我有一个大约有5,000,000行的MySQL表,通过DBI连接的并行Perl进程以小的方式不断更新.该表有大约10列和几个索引.
一个相当常见的操作有时会产生以下错误:
DBD::mysql::st execute failed: Deadlock found when trying to get lock; try restarting transaction at Db.pm line 276.
Run Code Online (Sandbox Code Playgroud)
触发错误的SQL语句是这样的:
UPDATE file_table SET a_lock = 'process-1234' WHERE param1 = 'X' AND param2 = 'Y' AND param3 = 'Z' LIMIT 47
Run Code Online (Sandbox Code Playgroud)
该错误仅在有时触发.我估计只有1%或更少的电话.然而,它从未发生在一个小桌子上,随着数据库的增长而变得越来越普遍.
请注意,我正在使用file_table中的a_lock字段来确保我运行的四个几乎相同的进程不会尝试在同一行上工作.该限制旨在将他们的工作分解成小块.
我没有在MySQL或DBD :: mysql上做太多调整.MySQL是标准的Solaris部署,数据库连接设置如下:
my $dsn = "DBI:mysql:database=" . $DbConfig::database . ";host=${DbConfig::hostname};port=${DbConfig::port}";
my $dbh = DBI->connect($dsn, $DbConfig::username, $DbConfig::password, { RaiseError => 1, AutoCommit => 1 }) or die $DBI::errstr;
Run Code Online (Sandbox Code Playgroud)
我在网上看到其他几个人报告了类似的错误,这可能是一个真正的僵局.
我有两个问题:
究竟是什么情况导致上述错误?
有一种简单的方法来解决它或减少它的频率?例如,我究竟如何"在Db.pm第276行重新启动交易"?
提前致谢.
防止代码死锁的常见解决方案是确保锁定顺序以通用方式发生,而不管哪个线程正在访问资源.
例如,给定线程T1和T2,其中T1访问资源A然后B和T2访问资源B然后A.按照需要的顺序锁定资源会导致死锁.简单的解决方案是锁定A然后锁定B,无论订单特定的线程将使用哪些资源.
问题情况:
Thread1 Thread2
------- -------
Lock Resource A Lock Resource B
Do Resource A thing... Do Resource B thing...
Lock Resource B Lock Resource A
Do Resource B thing... Do Resource A thing...
Run Code Online (Sandbox Code Playgroud)
可能解决方案
Thread1 Thread2
------- -------
Lock Resource A Lock Resource A
Lock Resource B Lock Resource B
Do Resource A thing... Do Resource B thing...
Do Resource B thing... Do Resource A thing...
Run Code Online (Sandbox Code Playgroud)
我的问题是在编码中使用了哪些其他技术,模式或常用做法来保证死锁预防?
等待死亡和伤口等待有什么区别?
我发现两种防止死锁的技术都做同样的事情(老回程的回滚).
可以任何机构解释我,他们与适当的例子有什么区别.
SQLServer自动记录所有死锁.任何人都可以帮助我获取sql查询,该查询将捕获正在收集的死锁数据,用于最近的事件.
我正在使用SQL SERVER 2008 R2进行开发活动.
谢谢和问候,Santosh Kumar Patro
除此之外我不知道我现在是否可以重现它(我已经使用这个特定的应用程序一两个星期没有问题),假设我在VS调试器中运行我的应用程序,如何它应该在它发生之后调试死锁吗?如果我暂停程序并因此看到不同的线程发生在哪里,我认为我可能能够获得调用堆栈,但是单击暂停只会使Visual Studio陷入死锁,直到我杀死我的应用程序.
除了浏览我的源代码树以寻找潜在问题之外,还有其他方法吗?一旦出现问题,是否有办法获得调用堆栈以查看问题所在?任何其他可能有用的工具/提示/技巧?
我了解到我应该解锁逆序以锁定订单.例如.
A.lock();
B.lock();
B.unlock();
A.unlock();
Run Code Online (Sandbox Code Playgroud)
但是,如果我这样做会发生什么:
A.lock();
B.lock();
A.unlock();
B.unlock();
Run Code Online (Sandbox Code Playgroud)
我尝试制作一个死锁场景,但如果我总是先锁定A然后B,那么我不知道会发生什么样的死锁.你能帮我吗?
我们的客户端代码检测到死锁,等待一段时间,然后重试请求最多5次.重试逻辑基于错误号1205检测死锁.
我的目标是在各种存储过程中测试死锁重试逻辑和死锁处理.我可以使用两个不同的连接创建死锁.但是,我想在单个存储过程本身内部模拟死锁.
死锁引发以下错误消息:
消息1205,第13级,状态51,第1行
事务(进程ID 66)在锁资源上与另一个进程发生死锁,并被选为死锁受害者.重新运行该交易.
我看到此错误消息在sys.messages:
select * from sys.messages where message_id = 1205 and language_id = 1033
message_id language_id severity is_event_logged text
1205 1033 13 0 Transaction (Process ID %d) was deadlocked on %.*ls resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
Run Code Online (Sandbox Code Playgroud)
我不能使用RAISERROR以下方法引发此错误:
raiserror(1205, 13, 51)
Run Code Online (Sandbox Code Playgroud)
消息2732,级别16,状态1,行1
错误号1205无效.号码必须是13000到2147483647,不能是50000.
我们的死锁重试逻辑检查错误号是否为1205.死锁需要具有与正常死锁相同的消息ID,级别和状态.
有没有办法模拟死锁(使用RAISERROR或任何其他方法)并只用一个进程获取相同的消息号?
我们的数据库使用SQL 2005兼容性,但我们的服务器在2005年到2008年之间有所不同.
我在Core Data中获得锁定.我真的不明白原因.因为我在后台线程中处理时正在创建背景MOC.下面你可以看到堆栈跟踪(我正在暂停应用程序的执行)看起来像这样:
Thread 1, Queue : com.apple.main-thread
#0 0x32d2a0fc in __psynch_mutexwait ()
#1 0x3608b128 in pthread_mutex_lock ()
#2 0x365d2dac in -[_PFLock lock] ()
#3 0x365e3264 in -[NSPersistentStoreCoordinator executeRequest:withContext:error:] ()
#4 0x365e1e2a in -[NSManagedObjectContext executeFetchRequest:error:] ()
#5 0x3664a93e in -[NSManagedObjectContext(_NestedContextSupport) _parentObjectsForFetchRequest:inContext:error:] ()
#6 0x3664b0c8 in __82-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]_block_invoke_0 ()
#7 0x3932bd28 in _dispatch_barrier_sync_f_slow_invoke ()
Thread 10, Queue : EventKitHelperSyncSerialBackgroundQueue
#0 0x32d19f04 in semaphore_wait_trap ()
#1 0x3932c300 in _dispatch_thread_semaphore_wait$VARIANT$mp ()
#2 0x3932a880 in _dispatch_barrier_sync_f_slow ()
#3 0x3663b9e6 in _perform ()
#4 0x3664adba in …Run Code Online (Sandbox Code Playgroud) 有时,我对存储过程只有一个Select查询有以下错误: Transaction (Process ID 91) was deadlocked on lock
我最初的理解是,一个select查询不会锁定一个表,或者即使它试图查询的表被另一个进程更新/锁定也不会导致死锁,但是看起来select查询会导致死锁好.
如果我将隔离级别设置为读取未提交的查询,那会解决问题吗?
deadlock ×10
sql ×3
c# ×2
concurrency ×2
database ×2
locking ×2
sql-server ×2
t-sql ×2
.net ×1
c++ ×1
cocoa ×1
cocoa-touch ×1
core-data ×1
ios ×1
mysql ×1
raiserror ×1
unit-testing ×1