我需要将信息从扫描数据的线程传递到记录信息线程(写入xml文件)。 它应该看起来像这样:
Application.Run() - 完成
扫描线程 - 完成
写入xlm线程 - ???
UI更新线程 - 我想我做到了
我现在得到了什么:
private void StartButtonClick(object sender, EventArgs e)
{
if (FolderPathTextBox.Text == String.Empty || !Directory.Exists(FolderPathTextBox.Text)) return;
{
var nodeDrive = new TreeNode(FolderPathTextBox.Text);
FolderCatalogTreeView.Nodes.Add(nodeDrive);
nodeDrive.Expand();
var t1 = new Thread(() => AddDirectories(nodeDrive));
t1.Start();
}
}
private void AddDirectories(TreeNode node)
{
string strPath = node.FullPath;
var dirInfo = new DirectoryInfo(strPath);
DirectoryInfo[] arrayDirInfo;
FileInfo[] arrayFileInfo;
try
{
arrayDirInfo = dirInfo.GetDirectories();
arrayFileInfo = dirInfo.GetFiles();
}
catch
{
return;
}
//Write data to xml file
foreach (FileInfo fileInfo in arrayFileInfo)
{
WriteXmlFolders(null, fileInfo);
}
foreach (DirectoryInfo directoryInfo in arrayDirInfo)
{
WriteXmlFolders(directoryInfo, null);
}
foreach (TreeNode nodeFil in arrayFileInfo.Select(file => new TreeNode(file.Name)))
{
FolderCatalogTreeView.Invoke(new ThreadStart(delegate { node.Nodes.Add(nodeFil); }));
}
foreach (TreeNode nodeDir in arrayDirInfo.Select(dir => new TreeNode(dir.Name)))
{
FolderCatalogTreeView.Invoke(new ThreadStart(delegate
{node.Nodes.Add(nodeDir);
}));
StatusLabel.BeginInvoke(new MethodInvoker(delegate
{
//UI update...some code here
}));
AddDirectories(nodeDir);
}
}
private void WriteXmlFolders(DirectoryInfo dir, FileInfo file)
{//writing information into the file...some code here}
如何将数据从AddDirectories(递归方法)线程传递给WriteXmlFolders线程?
答案 0 :(得分:1)
这是一个通用机制,一个线程如何生成另一个线程消耗的数据。无论采用何种方法(阅读:现成的类),您都会使用内部原理保持不变。主要参与者是(注意System.Threading
命名空间中有许多可用的锁定类,但这些类最适合这种情况:
AutoResetEvent
- 这允许线程进入睡眠模式(不消耗资源),直到另一个线程将其唤醒。 “自动”部分意味着一旦线程被唤醒,该类将被重置,以便下一个Wait()
调用将再次使其进入休眠状态,而无需重置任何内容。
ReaderWriterLock
或ReaderWriterLockSlim
(如果您使用的是.NET 4,建议使用第二个) - 这只允许一个线程锁定以写入数据,但多个线程可以读取数据。在这种特殊情况下,只有一个阅读线程,但如果有很多,则方法不会有所不同。
// The mechanism for waking up the second thread once data is available
AutoResetEvent _dataAvailable = new AutoResetEvent();
// The mechanism for making sure that the data object is not overwritten while it is being read.
ReaderWriterLockSlim _readWriteLock = new ReaderWriterLockSlim();
// The object that contains the data (note that you might use a collection or something similar but anything works
object _data = null;
void FirstThread()
{
while (true)
{
// do something to calculate the data, but do not store it in _data
// create a lock so that the _data field can be safely updated.
_readWriteLock.EnterWriteLock();
try
{
// assign the data (add into the collection etc.)
_data = ...;
// notify the other thread that data is available
_dataAvailable.Set();
}
finally
{
// release the lock on data
_readWriteLock.ExitWriteLock();
}
}
}
void SecondThread()
{
while (true)
{
object local; // this will hold the data received from the other thread
// wait for the other thread to provide data
_dataAvailable.Wait();
// create a lock so that the _data field can be safely read
_readWriteLock.EnterReadLock();
try
{
// read the data (add into the collection etc.)
local = _data.Read();
}
finally
{
// release the lock on data
_readWriteLock.ExitReadLock();
}
// now do something with the data
}
}
在.NET 4中,可以避免使用ReadWriteLock
并使用其中一个并发安全的集合,例如ConcurrentQueue
,这将在内部确保读/写是线程安全的。但是仍然需要AutoResetEvent
。
.NET 4提供了一种机制,可用于避免偶数AutoResetEvent
- BlockingCollection
的需要 - 此类提供了线程在数据可用之前休眠的方法。 MSDN page包含有关如何使用它的示例代码。
答案 1 :(得分:1)