- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我的问题是将 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/
我试图弄清楚接受 OpenID 登录的网站如何无法通过简单的主机文件更新来指向伪造的 OpenID 提供商。 假设我想侵入 Joe Smith 的帐户,在这个例子中,假设他的 OpenID 提供商是
#include #include #include #include #include #include #include #include #include #include #define P
根据此讨论 - "RESTful API - Correct behavior when spurious/not requested parameters are passed in the req
如果编译为 Cand C++ 源代码,这个简单的代码片段会使用 g++ 4.7.0 生成“函数调用中缺少标记”警告。我相信这是编译器的错误,因为最终的 NULL值(value)就在那里。 #inclu
我读到,有时 && 运算符用于“短路”JavaScript,使其相信返回值 0 是 0 而不是 NaN,因为 0 在 JavaScript 中是一个虚假数字。我一直在四处寻找,想弄清楚这一切意味着什么
我正在使用 Borland(又名“Embarcodegearland”)C++Builder 2007 编译器,它有一个小错误,系统头文件中的某些 static const 项可能导致虚假的 "xyz
我是一名优秀的程序员,十分优秀!