经过长时间的工作,我使用此方法multi-threading
无法取得任何成功。我非常感谢你的帮助。
我有listview
,其中第一列包含我们稍后将在其他方法中使用的网址。秒列用于结果。
我正在创建两个带有网址的ArrayLists
并将它们(带有arraylist的网址)发送到方法,然后在方法中,使用httpwebrequest
,我从每个网址获取网页标题
所以问题是当我尝试解雇5 threads
时,它就像:
(U:url,R:结果)
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
关键字与私有对象一起使用,但之后我丢失了multi-threading
。它的工作方式除了我之外一个接一个。不要同时触发5个不同的线程,并等待完成线程1移动到下一个线程。
/// Main Class ///
/* 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();
开始下载方法:
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中做了一个例子来说明它是如何工作的......
答案 0 :(得分:0)
我认为,这个方法存在一个问题:
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”)。您在列表视图的所有项目上运行一个循环,以查找FileDownloader的项目。为什么FileDownloader对他的项目一无所知?如果FileDownloader知道他的项目,那么你将不需要这个循环。并且你将在FileDownloader和他的Item之间有一个明确的链接。