C# 多线程方法的同步行为
在这方面花了很长时间后,我无法用这种方法成功地实现多线程。我真的很感谢你的帮助 我有一个C# 多线程方法的同步行为,c#,multithreading,listview,arraylist,C#,Multithreading,Listview,Arraylist,在这方面花了很长时间后,我无法用这种方法成功地实现多线程。我真的很感谢你的帮助 我有一个列表视图,其中第一列有我们稍后在其他方法中需要的URL。“秒”列用于显示结果 我创建了两个带有url的arraylist,并将它们(带有arraylist的url)发送到该方法,然后在该方法中,通过一个httpwebrequest,我从每个url获取页面标题 所以问题是,当我尝试启动5个线程时,它的工作原理如下: (U:url,R:result) u1=r1(因此,我必须将u1的结果作为r1..) 但我觉得:
列表视图
,其中第一列有我们稍后在其他方法中需要的URL。“秒”列用于显示结果
我创建了两个带有url的arraylist
,并将它们(带有arraylist的url)发送到该方法,然后在该方法中,通过一个httpwebrequest
,我从每个url获取页面标题
所以问题是,当我尝试启动5个线程时,它的工作原理如下:
(U:url,R:result)
u1=r1(因此,我必须将u1的结果作为r1..)
但我觉得:
u1=r1,u2=r1,u3(或4)=r1,u4=r1,u5=r2(或3,4)
但我期待的是:
u1=r1,u2=r2,u3=r3,u4=r4
要获得更好的解释,请查看下面的图片
然后我尝试对私有对象使用Lock
关键字,但随后我丢失了多线程
。它的工作原理与我所期望的一样,只是一个接一个。不要同时触发5个不同的线程,并等待完成线程1以移动到下一个线程
///主类///
/* A store of all created threads. */
ArrayList _threads = new ArrayList();
/* A store of all FileDownloader objects. */
ArrayList _instances = new ArrayList();
private int _activeDownloadCount = 0;
object _lockObject = new object();
按钮:
_instances = new ArrayList();
_threads = new ArrayList();
_activeDownloadCount = 0;
FileDownloader download = null;
foreach (ListViewItem item in listviewUrl.Items)
{
item.SubItems[9].Text = "Not started";
download = new FileDownloader(item.SubItems[0].Text);
item.Tag = download;
try
{
ThreadStart tsDelegate = new ThreadStart(download.Download);
download.DownloadStarting += new FileDownloader._delDownloadStarting(download_DownloadStarting);
download.DownloadCompleted += new FileDownloader._delDownloadCompleted(download_DownloadCompleted);
Thread t = new Thread(tsDelegate);
t.Name = item.SubItems[0].Text;
_threads.Add(t);
_instances.Add(download);
}
catch
{
item.SubItems[9].Text = "Error";
}
}
StartDownload();
StartDownload方法:
int j = 0;
int limit = int.Parse(numThreadSearch.Text);
int iCount = 0;
lock (_lockObject)
{
iCount = _instances.Count;
}
if (iCount != 0)
{
foreach (Thread thread in _threads)
{
FileDownloader file = ((FileDownloader)_instances[j]);
if (file._IsStarted == false)
{
lock (_lockObject)
{
thread.Start();
Console.WriteLine(_activeDownloadCount);
_activeDownloadCount++;
}
}
if (_activeDownloadCount == limit)
{
break;
}
j++;
}
}
else
{
/* If all the files have downloaded, we will do something here.
}
方法完成时:
void download_DownloadCompleted(FileDownloader thread, bool isSuccess)
{
lock (_lockObject)
{
_activeDownloadCount--;
}
PageRankReturns(FileDownloader._PageRankReturn, thread);
RemoveFromInternalPool(thread);
StartDownload();
}
delegate void delSetStatus(string Status, FileDownloader f);
private void PageRankReturns(string Status, FileDownloader f)
{
if (listviewUrl.InvokeRequired)
{
delSetStatus s = new delSetStatus(PageRankReturns);
this.Invoke(s, new object[] { Status, f });
}
else
{
foreach (ListViewItem item in listviewUrl.Items)
{
if (item.Tag == f)
{
/* Use locking to synchronise across mutilple thread calls. */
lock (_lockObject)
{
item.SubItems[2].Text = Status;
}
break;
}
}
}
}
private void RemoveFromInternalPool(FileDownloader thread)
{
int i = 0;
foreach (FileDownloader f in _instances)
{
if (f == thread)
{
/* If the file has downloaded, remove it from our pool. */
lock (_lockObject)
{
_threads.Remove(_threads[i]);
_instances.Remove(f);
break;
}
}
i++;
}
}
///二等舱///
#region Fields
private string _DocumentUrl = string.Empty;
private string _DirectoryPath = string.Empty;
public bool _IsDownloading = false;
public bool _IsDownloadSuccessful = false;
public bool _IsStarted = false;
#endregion
#region Delegates
public delegate void _delDownloadStarting(FileDownloader thread);
public delegate void _delDownloadCompleted(FileDownloader thread, bool isSuccess);
public delegate void _delDownloadCWorking(FileDownloader thread);
#endregion
#region Events
public event _delDownloadStarting DownloadStarting;
public event _delDownloadCompleted DownloadCompleted;
protected static readonly object locker = new object();
public static string pageTitleResult= string.Empty;
public static string _pageTitleResult
{
get { return pageTitleResult; }
}
public FileDownloader(string documentUrl)
{
_DocumentUrl = documentUrl;
}
//下载方法//
public void Download()
{
_IsStarted = true;
DownloadStarting(this);
_IsDownloading = true;
_IsDownloadSuccessful = false;
// with lock keyword it works one by one//
//without lock or monitor.enter keyword then it works as i tried explain above u1 = r1, u2 = r1, ur3 = r1, u4=r3 etc...
try
{
string pageHtml = getHtml(_DocumentUrl);
HtmlAgilityPack.HtmlDocument htmlDoc = new HtmlAgilityPack.HtmlDocument();
//html agibility works with returned string from gethtml...
// string pageTitle = html agibility work result, it's string...
pageTitleResult = pageTitle
_IsDownloadSuccessful = true;
_IsDownloading = false;
/* raise a download completed event. */
DownloadCompleted(this, _IsDownloadSuccessful);
}
catch
{
_IsDownloadSuccessful = false;
}
Thread.Sleep(10);
}
锁定对象:
protected static readonly object locker = new object();
我刚刚用excel做了一个例子来说明它是如何工作的
这是不带锁的返回关键字:
这是用lock关键字,顺便说一下,在这个例子中,激发了5个线程,但它等待第一个线程的结束。。。
这就是我想做的。。。
我认为,这种方法存在一个问题:
private void PageRankReturns(string Status, FileDownloader f)
{
if (listviewUrl.InvokeRequired)
{
delSetStatus s = new delSetStatus(PageRankReturns);
this.Invoke(s, new object[] { Status, f });
}
else
{
foreach (ListViewItem item in listviewUrl.Items)
{
if (item.Tag == f)
{
/* Use locking to synchronise across mutilple thread calls. */
lock (_lockObject)
{
item.SubItems[2].Text = Status;
}
break;
}
}
}
}
您必须更改应用程序的结构。
请参阅上面的方法(“PageRankReturns”)。在listview的所有项目上运行一个循环,以查找FileDownloader的项目。为什么FileDownloader对他的项目一无所知?如果FileDownloader知道他的项目,那么您就不需要这个周期。您将在FileDownloader和他的项目之间有一个明确的链接。“PageTitlerResult=pageTitle;”-什么是“PageTitlerResult”,“pageTitle”?它们的定义和用途在哪里?@AlexanderKiselev我刚刚编辑了这部分。。这只是html敏捷性包的工作,不管有没有它,线程问题都不会改变,这就是为什么我删除了这一部分以稍微清除代码。我在代码中找不到将字符串插入ListView列的位置:item.Subitems[1],其中是url,item.Subitems[2],结果在哪里,如果我正确理解了您的帖子。@AlexanderKiselev感谢您的时间alexander,我刚刚添加了用于多线程的其他必要方法。在方法PageRankReturns()中,尝试“if(f.Equals(item.Tag))”而不是“if(item.Tag==f)”。结果相同。我认为最好检查所有代码。从这里开始:。对于我所做的改变,你可以从上面看到。好吧,我想我会继续并行,我仍然无法解决这个问题@亚历山大·基塞列夫