【发布时间】:2011-12-01 09:53:30
【问题描述】:
我有一个多线程程序,它打开几个线程来查询外部 CRM 并将结果保存在内存中的 IDictionary 中以加快系统速度。
我对多线程和关键部分有点困惑。我希望我的班级QueryThreadProcess 有一个运行查询并管理启动和停止查询的线程。它有一个查询类型的对象并将结果保存在一个列表中。
QueryManager 类将杀死所有进程或启动所有进程,基本上是集合范围的方法。
我感觉QueryThreadProcess 的私有成员在所有线程之间共享。我怎样才能使它们对每个线程私有,但也可以将每个线程与外部类分开杀死?
我不想锁定,因为我希望所有线程并行运行。
这是我的经理班:
public class QueryManager
{
private IDictionary<int, QueryThreadProcess> _queries;
public QueryManager()
{
_queries = new Dictionary<int, QueryThreadProcess>();
}
public void Start()
{
CreateQueryThreadsFromDb();
StartAllThreads();
}
private void StartAllThreads()
{
if (_queries != null && _queries.Count > 0)
{
StopThreadsAndWaitForKill();
}
foreach (var query in _queries)
query.Value.Start();
}
private void CreateQueryThreadsFromDb()
{
var queries = new QueryProvider().GetAllQueries();
if (_queries != null && _queries.Count > 0)
{
StopThreadsAndWaitForKill();
_queries.Clear();
}
foreach (var query in queries)
_queries.Add(query.Id, new QueryThreadProcess(query));
}
private void StopThreadsAndWaitForKill()
{
KillAllThreads();
while (!AreAllThreadsKilled()) { }
}
private void KillAllThreads()
{
foreach (var query in _queries)
query.Value.Kill();
}
private bool AreAllThreadsKilled()
{
return _queries.All(query => query.Value.IsKilled);
}
public IList<User> GetQueryResultById(int id)
{
return _queries[id].Result;
}
}
这是我的 QueryProcesses 类,它包含执行实际查询的线程:
using System.Collections.Generic;
using System.Threading;
using Intra.BLL.MessageProviders;
using Intra.BO;
using Intra.BO.Messages;
namespace Intra.BLL.QueryProcess
{
internal class QueryThreadProcess
{
private readonly Thread _thread;
private readonly Query _query;
private bool _isStoppingQuery = false;
private bool _isKilled = true;
private IList<User> _result;
private readonly object _objSync = new object();
public QueryThreadProcess(Query query)
{
_query = query;
_thread = new Thread(RetrieveQueries);
}
public void Start()
{
_isStoppingQuery = true;
while (!_isKilled) { }
_isStoppingQuery = false;
_thread.Start();
}
private void RetrieveQueries()
{
const string BROKERNAME = "bla";
_isKilled = false;
while (!_isStoppingQuery)
{
Broker broker = new BrokerProvider().GetBrokerByName(BROKERNAME);
var users = new QueryProvider().GetUserObjectsByQuery(_query, ParaTokenGenerator.GetBrokerAuthToken(broker));
_result = users;
}
_isKilled = true;
}
public bool IsKilled
{
get { return _isKilled; }
}
public IList<User> Result
{
get
{
lock (_objSync)
return _result;
}
}
public void Kill()
{
_isStoppingQuery = true;
}
}
}
【问题讨论】:
-
您正在为每个查询创建一个 QueryThreadProcess 实例,因此不会发生私有成员共享,因为每个实例都是完全独立的。
-
QueryThreadProcess 的私有成员确实是每个实例私有的。也就是说,QueryManager 中的 _queries 字典不是线程安全的,所以我建议锁定对字典的任何访问。此外,如果您希望同时调用其中一些方法,则可能存在其他竞争条件的微妙之处。
标签: c# asp.net .net multithreading