创建同步对象






4.75/5 (4投票s)
如何使用 ISynchronizeInvoke 接口创建同步对象,就像 FileSystemWatcher 中那样。
引言
你是否曾经需要一个 SynchronizingObject
用于多线程应用程序?
假设你想像这个演示程序那样列出文件,并且从一个与 UI 运行线程不同的工作线程获取文件,那么你将会遇到跨线程异常,这会导致你编写额外的代码,仅仅是为了解决它,对吧?
如果你熟悉 FileSystemWatcher
类,你可能已经注意到 SynchronizingObject
,你可以将你的 UI 表单分配给它,从而避免跨线程异常。
很好,SynchronizingObject
的类型是 ISynchronizeInvoke
,所有 System.Windows.Forms.Control
都从它派生。这意味着所有控件都可以添加到此属性中。不错吧?
背景
一位朋友问我关于跨线程异常的问题。
使用代码
这个演示程序没有实现 ISynchronizeInvoke
接口,它会将它用作自定义类上的一个属性。
如果你想了解更多关于实现 ISynchronizeInvoke
接口的信息,我推荐这篇不错的 CP 文章:https://codeproject.org.cn/KB/cs/delegatequeue.aspx。
好的,回到我的文章,希望如此;o)
FileEventArgs 类
它非常简单。它包含有关我的自定义列表类将返回的文件总数的信息,文件在列表中的当前位置,以及当前文件的文件信息。
public class FileEventArgs : EventArgs
{
int _current;
int _total;
FileSystemInfo _file;
public int Current
{
get { return _current; }
}
public int Total
{
get { return _total; }
}
public FileSystemInfo File
{
get { return _file; }
}
internal FileEventArgs(int current, int total, FileSystemInfo file)
{
_current = current;
_total = total;
_file = file;
}
}
FileEventHandler 委托
它将用于我的自定义列表类上的事件。
public delegate void FileEventHandler(object sender, FileEventArgs e);
FileLister 类
我在代码中添加了注释...
public class FileLister
{
public event FileEventHandler IncommingFile;
//Event that handles incomming files...
public event EventHandler FileListDone;
//Event that handles when list is done...
private Thread BackGroundThread; //local background worker.
private ISynchronizeInvoke synchronizingObject;
//Contains the object to Sync up against.
[Browsable(false), DefaultValue((string)null)]
public ISynchronizeInvoke SynchronizingObject
//Property to get or set the object to Sync up against.
{
get { return this.synchronizingObject; }
set { this.synchronizingObject = value; }
}
protected void OnIncommingFile(FileEventArgs e)
{
if (this.IncommingFile != null)
//if the IncommingFile event is not null.
//(meaning that an subscriber to the event is present...)
{
//SynchronizingObject is not null and the Synchronizing
//Object Requires and invokation...
if ((this.SynchronizingObject != null) &&
this.SynchronizingObject.InvokeRequired)
this.SynchronizingObject.BeginInvoke(IncommingFile,
new object[] { this, e });
//Get the Synchronizing Object to invoke the event...
else
IncommingFile(this, e); //Fire the event
}
}
protected void OnFileListDone()
{
if (this.FileListDone != null)
//if the FileListDone event is not null.
//(meaning that an subscriber to the event is present...)
{
//SynchronizingObject is not null and
//the Synchronizing Object Requires and invokation...
if ((this.SynchronizingObject != null) &&
this.SynchronizingObject.InvokeRequired)
this.SynchronizingObject.BeginInvoke(FileListDone,
new object[] { this, null });
//Get the Synchronizing Object to invoke the event...
else
FileListDone(this, null); //Fire the event
}
}
public void ListFilesFrom(string path)
{
//create and BackgroundWorker thread, with parameters...
BackGroundThread =
new Thread(new ParameterizedThreadStart(getFilesInNewThread));
BackGroundThread.Start(path); //Start the Thead with the parameter...
}
private void getFilesInNewThread(object path)
{
//get the parameter which is the path
//to where the list should list files from.
string folderpath = path.ToString();
if (Directory.Exists(folderpath))
//if the folder exists...
{
//Create an new instance of the DirectoryInfo class,
//which can get an array if FileSystemInfo objects.
DirectoryInfo di = new DirectoryInfo(folderpath);
//Get the FileSystemInfo objects...
FileSystemInfo[] files = di.GetFileSystemInfos();
int total = files.Length; //Get total cound of files to send to GUI.
for (int i = 0; i < total; i++) // loop through the array..
OnIncommingFile(new FileEventArgs(i, total, files[i]));
//Send one file at the time through the event.
//(NOTE: normaly this would not be the case, as one would send
// the hole array in one piece. but for demo reason this is so...)
}
OnFileListDone(); //Fire the Event saying the loop is done...
}
public void StopFilelistEnumeration()
{
if (BackGroundThread != null && BackGroundThread.IsAlive)
//if the backgroundworker thread is not null and is running then...
BackGroundThread.Abort(); //Abort/kill the thread.
}
}
请查看演示程序!!!
有关如何使用该类及其 SynchronizingObject
的更多信息,请参阅演示程序。
关注点
通过这个小示例,我的朋友能够创建更线程安全的类。
希望你能够使用它...
历史
- 2009 年 8 月 25 日:文章发布。