背景
我正在开发一个小应用程序,它将通过WMI远程读取事件日志中的事件。基本上我正在寻找工作站锁定和解锁的时间。
问题:
我创建了一个线程数组。我遍历我的数据集(计算机名)并启动多个 带有自定义对象的ParameterizedThreadStart对象(LockHunterArgs)。问题是我知道我的数据集中没有重复项。我在一个线程函数的末尾添加了一个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数组,并在线程触发过程中创建和分配它们,但这也没有用。
这可能是愚蠢的。提前谢谢。
// lance
代码:
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>();
}
答案 0 :(得分:0)
使用temp变量存储迭代值:
foreach (LINQ.session sesson in currentSessions)
{
var tempSession = session; // now use tempSession
....
这是关闭迭代值的已知副作用。
答案 1 :(得分:0)
我会说问题最有可能发生在你剪掉的东西上。我无法使用这些伪造的数据重现您的问题:
var guids = Enumerable.Range(1, 10)
.Select(i => Guid.NewGuid())
.ToArray();
var currentSessions = Enumerable.Range(1, 10)
.Select(i => new {computername = "pc" + i})
.Zip(guids,(a,g) => new {a.computername, uid = g});
var dbactions = Enumerable.Range(1, 10)
.Select(i => DateTime.Now.AddHours(-1*i))
.Zip(guids, (t,g) => new {session_id = g, timestamp = t});
鉴于此,您能否提供一个不依赖于任何本地资源的工作示例?