gpt4 book ai didi

c# - 将(结构的)实例方法传递给 ThreadStart 似乎更新了一个虚假实例,因为原始实例不受影响

转载 作者:太空宇宙 更新时间:2023-11-03 22:09:09 26 4
gpt4 key购买 nike

我的问题是将 this.folderFolder 实例方法传递给 ThreadStart 构造函数。我使用 dirAssThread 单步执行它并观察它正确更新实例数据成员并完成,然后我回到

if (dirAssThread.IsAlive) completeThread(-1); //***ie abort

并发现我通过方法传递给 ThreadStart 构造函数的同一个 this 实例的数据成员已奇迹般地将自身重置为 0!

这里是其他函数

using System;
using System.IO;
using System.Threading;

namespace MonitorService
{
struct myStruct
{
long bytesSzMember;
Thread dirAssThread;
private Object thisLock;

private void completeThread(long bytesSzNew)
{
lock (thisLock)
{
if (bytesSzNew == -1)
{
dirAssThread.Abort();
Console.WriteLine("A thread timed out.");
}
else
{
bytesSzMember = bytesSzNew;
Console.WriteLine("A thread update size.");
}
}
}

private void folderFolder()
{
long bytesSzNew = 0;
DirectoryInfo di = new DirectoryInfo("C:\\SomeDir");
DirectoryInfo[] directories = di.GetDirectories("*",SearchOption.AllDirectories);
FileInfo[] files = di.GetFiles("*",SearchOption.AllDirectories);
foreach (FileInfo file in files)
{
bytesSzNew += file.Length;
}
completeThread(bytesSzNew);
}

private void updateSize()
{
thisLock = new Object();
dirAssThread = new Thread(new ThreadStart(this.folderFolder));
dirAssThread.Start();
Thread.Sleep(5000);
if (dirAssThread.IsAlive) completeThread(-1);
}
}
}

最佳答案

更新

问题标题更新后,您看到的问题是结构是根据引用复制的。将委托(delegate)分配给线程时,您正在传递结构的副本,线程将更新该副本。当您检查 completeThread 时,它是针对尚未更新的原始文件。

使用类而不是结构。

替代解决方案

我建议使用等待句柄而不是 sleep 和线程中止,因为 Thread.Abort 被认为是一种危险的做法,应该避免(在这种情况下很容易)。我提出以下解决方案,它是一个递归版本,不会遵循循环引用(因此实际上不需要中止,如果您不想要超时设施,可以删除代码)。

public class WaitForFileSizes
{
private readonly object _syncObj = new object();
private readonly HashSet<string> _seenDirectories = new HashSet<string>();
private readonly ManualResetEvent _pEvent = new ManualResetEvent(false);
private long _totalFileSize;
private Thread _thread;
private volatile bool _abort;

private void UpdateSize()
{
_thread = new Thread(GetDirectoryFileSize);
_thread.Start();

bool timedout = !_pEvent.WaitOne(5000);

if (timedout)
{
_abort = true;
_pEvent.WaitOne();
Console.WriteLine("A thread timed out.");
}
else
{
Console.WriteLine("Total size {0}b.", _totalFileSize);
}
}

private void GetDirectoryFileSize()
{
GetDirectoryFileSizesRecursively(new DirectoryInfo("C:\\temp"));

_pEvent.Set();
}

private void GetDirectoryFileSizesRecursively(DirectoryInfo dir)
{
Parallel.ForEach(dir.EnumerateFiles(), f =>
{
if (_abort)
{
_pEvent.Set();
return;
}

Interlocked.Add(ref _totalFileSize, f.Length);
});

Parallel.ForEach(dir.EnumerateDirectories(), d =>
{
if (!IsSeen(d))
{
GetDirectoryFileSizesRecursively(d);
}
});
}

private bool IsSeen(DirectoryInfo dir)
{
lock (_syncObj)
{
if (!_seenDirectories.Contains(dir.FullName))
{
_seenDirectories.Add(dir.FullName);

return false;
}

return true;
}
}
}

更新

因为我们现在有循环引用检测,所以可以删除线程和中止代码,因为如果线程处于无限循环中,以前在那里会中止线程——现在不需要了:

public class WaitForFileSizes
{
private readonly object _syncObj = new object();
private readonly HashSet<string> _seenDirectories = new HashSet<string>();
private long _t;

public void UpdateSize()
{
GetSize(new DirectoryInfo("C:\\temp"));

Console.WriteLine("Total size {0}b.", _t);
}

private void GetSize(DirectoryInfo dir)
{
Parallel
.ForEach(dir.EnumerateFiles(), f => Interlocked.Add(ref _t, f.Length));

Parallel
.ForEach(dir.EnumerateDirectories().Where(IsNewDir), GetSize);
}

private bool IsNewDir(FileSystemInfo dir)
{
lock (_syncObj)
{
if (!_seenDirectories.Contains(dir.FullName))
{
_seenDirectories.Add(dir.FullName);
return true;
}
return false;
}
}
}

关于c# - 将(结构的)实例方法传递给 ThreadStart 似乎更新了一个虚假实例,因为原始实例不受影响,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7318225/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com