【发布时间】:2012-03-30 01:45:10
【问题描述】:
背景:
我正在开发一个小型应用程序,该应用程序将通过 WMI 从事件日志中远程读取事件。基本上我正在寻找工作站何时锁定和解锁。
问题:
我创建了一个线程数组。我遍历我的数据集(计算机名称)并启动多个 带有自定义对象 (LockHunterArgs) 的 ParameterizedThreadStart 对象。问题是我知道我的数据集没有重复项。我在线程函数的末尾添加了一个 console.writeline,它显示了重复项。
另外,在我尝试使用线程之前。如果我同步运行代码,它运行良好。只是花了很长时间。所以这就是我尝试引入多线程的原因。
示例输出:
//...在上面剪掉了一些独特的行
计算机:COMP 时间:2012 年 3 月 29 日上午 8:05:11 会话:3935dd76-6a10-41a9-bd96-86143c66482d 计算机:COMP 时间:2012 年 3 月 29 日上午 8:05:11 会话:3935dd76-6a10-41a9-bd96-86143c66482d
//...在下面剪掉一些独特和重复的行
我的假设:
如果我在 get_lock_data 函数的前几行放置一个断点,它正在转换并跳到下一行。这是随机的。它会向前走一次,然后两次击中同一条线。我什至看到它向下走两行然后向后走。我认为这是因为我正在触发线程并且它在不同的时间达到了点,给人一种它正在倒退的错觉。但这几乎就像传入的对象被后面的线程覆盖一样。
我尝试创建另一个 LockHunterArgs 数组并在线程触发过程中创建和分配它们,但这也没有用。
这可能是愚蠢的。提前致谢。
// 长矛
代码:
public class LockHunterArgs
{
public LockHunterArgs(string comp, DateTime limit, Guid session)
{
Computer = comp;
LimitTime = limit;
sessionID = session;
}
public string Computer;
public DateTime LimitTime;
public Guid sessionID;
}
public class LockHunter
{
private void get_lock_data(object args)
{
string computer = ((LockHunterArgs)args).Computer;
DateTime limitTime = ((LockHunterArgs)args).LimitTime;
Guid sessionID = ((LockHunterArgs)args).sessionID;
//....SNippet ... code connects to the box and pulls data...
Console.WriteLine("Computer: " + computer + " Time: " + limitTime.ToString() + " Session: " + sessionID.ToString());
}
public void HuntLocks()
{
//....Snippet... code connects to database and gets a list of objects (currentSessions)
Thread[] threadArray = new Thread[currentSessions.Count];
int cnt = 0;
foreach (LINQ.session sesson in currentSessions)
{
DateTime mostRecentTimestamp = (from q in db.actions
where q.session_id == sesson.uid
orderby q.timestamp descending
select q.timestamp).FirstOrDefault();
ParameterizedThreadStart start = new ParameterizedThreadStart(get_lock_data);
threadArray[cnt] = new Thread(start);
threadArray[cnt].Start(new LockHunterArgs(sesson.computername , mostRecentTimestamp, sesson.uid));
cnt++;
}
for (int i = 0; i < threadArray.Length; i++)
{
threadArray[i].Join();
}
Console.WriteLine(DateTime.Now.ToString() + " Threads have joined");
//....Snippet of saving the gathered data from the threads to the database
}
}
解决方案:
我添加了一个新课程。然后遍历我的 LINQ-to-SQL 结果以创建该新类的列表。然后,我从该列表而不是 LINQ-to-SQL 生成的列表中触发我的线程。一切都很好。谁能解释一下?
public class TempSession
{
public TempSession(LINQ.session sess)
{
this.computername = sess.computername;
this.timestamp = sess.start_time;
this.uid = sess.uid;
}
public string computername;
public DateTime timestamp;
public Guid uid;
}
public void HuntLocks()
{
//select EventCode,TimeGenerated,Message from Win32_NTLogEvent WHERE logfile='Security' and (EventCode='4800' or EventCode='4801') and TimeGenerated > '20120327 08:08:08'
// 4800 = locked
// 4801 = unlocked
LINQ.Login_ActionsDataContext db = new LINQ.Login_ActionsDataContext();
List<LINQ.session> currentSessions = (from q in db.sessions
where q.end_time == null
orderby q.computername ascending
select q).ToList();
// START Solution Changes
List<TempSession> newCurrentSessions = new List<TempSession>();
foreach (LINQ.session session in currentSessions)
{
newCurrentSessions.Add(new TempSession(session));
}
Thread[] threadArray = new Thread[newCurrentSessions.Count];
// END solution changes
for (int i = 0; i < newCurrentSessions.Count; i++)
{
DateTime mostRecentTimestamp = (from q in db.actions
where q.session_id == newCurrentSessions[i].uid
orderby q.timestamp descending
select q.timestamp).FirstOrDefault();
ParameterizedThreadStart start = new ParameterizedThreadStart(get_lock_data);
threadArray[i] = new Thread(start);
threadArray[i].Start(new LockHunterArgs(newCurrentSessions[i].computername, mostRecentTimestamp, newCurrentSessions[i].uid));
}
for (int i = 0; i < threadArray.Length; i++)
{
threadArray[i].Join();
}
Console.WriteLine(DateTime.Now.ToString() + " Threads have joined");
db.actions.InsertAllOnSubmit(newActions);
Console.WriteLine(DateTime.Now.ToString() + " Found " + newActions.Count.ToString() + " locks");
db.SubmitChanges();
newActions = new List<LINQ.action>();
}
【问题讨论】:
-
既然我们知道这不是一个闭包问题,我的直觉让我认为这与在遍历集合时进行另一个 Linq To SQL 调用有关。新代码在进行另一个 linq to sql 调用时不会迭代 linq to SQL 生成的列表。它现在使用一个简单的 for 循环索引计数器。
标签: c# multithreading