我有一个应用程序,在创建一个线程之前,它调用数据库来提取X条记录。从数据库中检索记录时,将设置锁定标志,以便不再拉动这些记录。
一旦线程完成,它将从该数据库中提取更多记录。当我从一个线程调用数据库时,我应该对该段代码设置一个锁定,以便当时只有那个线程调用它?这是我的代码的例子(我在我有锁的区域评论过):
private void CreateThreads()
{
for(var i = 1; i <= _threadCount; i++)
{
var adapter = new Dystopia.DataAdapter();
var records = adapter.FindAllWithLocking(_recordsPerThread,_validationId,_validationDateTime);
if(records != null && records.Count > 0)
{
var paramss = new ArrayList { i, records };
ThreadPool.QueueUserWorkItem(ThreadWorker, paramss);
}
this.Update();
}
}
private void ThreadWorker(object paramList)
{
try
{
var parms = (ArrayList) paramList;
var stopThread = false;
var threadCount = (int) parms[0];
var records = (List<Candidates>) parms[1];
var runOnce = false;
var adapter = new Dystopia.DataAdapter();
var lastCount = records.Count;
var runningCount = 0;
while (_stopThreads == false)
{
if (records.Count > 0)
{
foreach (var record in records)
{
var proc = new ProcRecords();
proc.Validate(ref rec);
adapter.Update(rec);
if (_stopThreads)
{
break;
}
}
//This is where I think I may need to sync the threads.
//Is this correct?
lock(this){
records = adapter.FindAllWithLocking;
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
SQL to Pull记录:
WITH cte AS (
SELECT TOP (@topCount) *
FROM Candidates WITH (READPAST)
WHERE
isLocked = 0 and
isTested = 0 and
validated = 0
)
UPDATE cte
SET
isLocked = 1,
validationID = @validationId,
validationDateTime = @validationDateTime
OUTPUT INSERTED.*;
答案 0 :(得分:2)
您不需要锁定线程,因为数据库应该根据您的请求执行此操作。
答案 1 :(得分:1)
我看到了一些问题。
首先,您正在测试_stopThreads == false
,但您尚未透露这是否是一个易变的读取。阅读answer的一半中的第二个,以便对我所谈论的内容有一个很好的描述。
其次,锁是没有意义的,因为adapter
是对非共享对象的本地引用,而records
是一个刚被替换的本地引用。我假设适配器与数据库建立了单独的连接,但如果它共享现有连接,则可能需要进行某种类型的同步,因为ADO.NET连接对象通常不是线程安全的。
现在,您可能需要在某处锁定以发布工作项的结果。我没有看到结果发布到主线程的位置,所以我不能在这里提供任何指导。
顺便说一下,我会避免在ThreadPool
帖子中显示一个消息框。原因是这将挂起该线程,直到消息框关闭。
答案 2 :(得分:0)
你不应该锁定(这个),因为你很容易创建死锁,你应该创建一个单独的锁对象。如果您搜索“锁定(此)”,您可以找到许多关于原因的文章。
这是关于lock(this)
的SO问题