WaitHandle.WaitAny() & WaitHandle.WaitAll() usage problem
My application is not exiting properly. I am just trying to print the total number of connections, after that waiting for all the upload operations to complete, and then quit gracefully.
Below is the code...
using System;
using System.Net;
using System.Threading;
using System.IO;
using System.Text;
namespace ServicePointDemo
{
class Program
{
struct UploadState
{
public string Filename;
public AutoResetEvent are;
}
static void Main(string[] args)
{
AutoResetEvent are = new AutoResetEvent(false);
ServicePoint sp = ServicePointManager.FindServicePoint(new Uri("ftp://xxx.xxx.xxx.xxx/public"));
UploadState us1 = new UploadState();
us1.are = new AutoResetEvent(false);
us1.Filename = @"C:\inventory.xls";
UploadState us2 = new UploadState();
us2.are = new AutoResetEvent(false);
us2.Filename = @"C:\somefile.txt";
Thread t1, t2;
t1 = new Thread(new ParameterizedThreadStart(DoUpload));
t2 = new Thread(new ParameterizedThreadStart(DoUpload));
t1.Start(us1);
t2.Start(us2);
Console.WriteLine("Waiting for something to trigger up");
WaitHandle.WaitAny(new WaitHandle[] { us1.are, us2.are });
Console.WriteLine("CurrentConnections = {0}", sp.CurrentConnections);
Console.WriteLine("Waiting for all operations to complete...");
WaitHandle.WaitAll(new WaitHandle[] { us1.are, us2.are });
Console.WriteLine("Press enter to quit");
Console.ReadLine();
}
static void DoUpload(object state)
{
string filename = ((UploadState)state).Filename;
FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.Create("ftp://172.16.130.22/public/" + Path.GetFileName(filename));
Console.WriteLine("Upload URI = {0}", ftpRequest.RequestUri.AbsoluteUri);
ftpRequest.Method = WebR开发者_高级运维equestMethods.Ftp.UploadFile;
ftpRequest.Credentials = new NetworkCredential("anonymous", "guest@");
ftpRequest.Proxy = new WebProxy();
Stream stream = null;
FileStream file = new FileStream(filename, FileMode.Open);
Console.WriteLine("Total file size of {0} = {1}", filename, file.Length);
StreamReader rdr = new StreamReader(file);
Console.WriteLine("Getting bytes of {0}", filename);
byte[] fileBytes = Encoding.ASCII.GetBytes(rdr.ReadToEnd());
rdr.Close();
Console.WriteLine("Acquiring connection of {0} upload...", filename);
try
{
stream = ftpRequest.GetRequestStream();
Console.WriteLine("Upload of {0} has acquired a connection", filename);
((UploadState)state).are.Set();
stream.Write(fileBytes, 0, fileBytes.Length);
Console.WriteLine("Uploading {0} complete", filename);
}
catch (Exception ex)
{
Console.WriteLine("Exception has occurred: {0}", ex.Message);
}
finally
{
Console.WriteLine("Ending uploading {0}", filename);
stream.Close();
((UploadState)state).are.Set();
}
Console.WriteLine("Quit DoUpload() for {0}", filename);//...is not executed(?)
}
}
}
You seem to have a race condition on your AutoResetEvents
If the threads run quickly they could call Set() on the auto reset event twice before the main thread has reached the first WaitAny(). This would then allow it to pass the first WaitAny() but will block on the WaitAll() because neither thread does any more calls to Set(). (You can simulate this by putting a long Thread.Sleep() in the main thread right after you have started the two background threads)
I would suggest you use two separate AutoResetEvents (Or just plain EventWaitHandles) one that is Set() when the connection is acquired, and one that is set when it is complete, so you don't rely on the timing of the threads.
Replace the WaitAll() call with a call to Join() on each thread.
By the way, you don't need the very first AutoResetEvent are
in Main() as it is not used.
精彩评论