我一直在尝试解决此“并行编程”考试练习(在C#中):
知道Stream该类包含int Read(byte[] buffer, int offset, int size)和void Write(byte[] buffer, int offset, int size)方法,就可以在C#中实现NetToFile将从NetworkStream net实例接收的所有数据复制到FileStream file实例的方法。要进行传输,请使用异步读取和同步写入,以避免在读取操作期间阻塞一个线程。当net读取操作返回值0 时,传输结束。为简化起见,不必支持操作的受控取消。
Stream
int Read(byte[] buffer, int offset, int size)
void Write(byte[] buffer, int offset, int size)
NetToFile
NetworkStream net
FileStream file
net
void NetToFile(NetworkStream net, FileStream file);
我一直在尝试解决此问题,但我一直在努力解决与问题本身相关的问题。但是首先,这是我的代码:
public static void NetToFile(NetworkStream net, FileStream file) { byte[] buffer = new byte[4096]; // buffer with 4 kB dimension int offset = 0; // read/write offset int nBytesRead = 0; // number of bytes read on each cycle IAsyncResult ar; do { // read partial content of net (asynchronously) ar = net.BeginRead(buffer,offset,buffer.Length,null,null); // wait until read is completed ar.AsyncWaitHandle.WaitOne(); // get number of bytes read on each cycle nBytesRead = net.EndRead(ar); // write partial content to file (synchronously) fs.Write(buffer,offset,nBytesRead); // update offset offset += nBytesRead; } while( nBytesRead > 0); }
我的问题是,在问题陈述中说:
要进行传输,请使用异步读取和同步写入,避免在读取操作期间阻塞一个线程
我不确定我的解决方案是否能够完成本练习中需要的功能,因为我一直AsyncWaitHandle.WaitOne()在等异步读取完成。
AsyncWaitHandle.WaitOne()
另一方面,在这种情况下,我并没有真正弄清楚什么是“非阻塞”解决方案,因为FileStream写入是要同步进行的……为了做到这一点,我必须等到NetworkStream阅读完成后继续FileStream写作,不是吗?
FileStream
NetworkStream
您能帮我这个忙吗?
[编辑1] 使用 回调 解决方案
好的,如果我了解Mitchel Sellers和willvv的回答,则建议我使用回调方法将其转换为“非阻塞”解决方案。这是我的代码,然后:
byte[] buffer; // buffer public static void NetToFile(NetworkStream net, FileStream file) { // buffer with same dimension as file stream data buffer = new byte[file.Length]; //start asynchronous read net.BeginRead(buffer,0,buffer.Length,OnEndRead,net); } //asynchronous callback static void OnEndRead(IAsyncResult ar) { //NetworkStream retrieve NetworkStream net = (NetworkStream) ar.IAsyncState; //get number of bytes read int nBytesRead = net.EndRead(ar); //write content to file //... and now, how do I write to FileStream instance without //having its reference?? //fs.Write(buffer,0,nBytesRead); }
您可能已经注意到,由于无法引用FileStream要调用“ Write(…)”方法的实例,因此我陷入了回调方法。
此外,这不是线程安全的解决方案,因为该byte[]字段是公开的,并且可以在并发NetToFile调用之间共享。我不知道如何解决这个问题而不将其暴露byte[]在外层视野中……我几乎可以肯定它可能不会以这种方式暴露出来。
byte[]
我不想使用lambda或匿名方法解决方案,因为这不在“并发编程”课程的课程中。
您将需要使用NetStream读取的回调来处理此问题。坦率地说,将复制逻辑包装到其自己的类中可能会更容易,以便您可以维护活动Streams的实例。
这是我的处理方式(未经测试):
public class Assignment1 { public static void NetToFile(NetworkStream net, FileStream file) { var copier = new AsyncStreamCopier(net, file); copier.Start(); } public static void NetToFile_Option2(NetworkStream net, FileStream file) { var completedEvent = new ManualResetEvent(false); // copy as usual but listen for completion var copier = new AsyncStreamCopier(net, file); copier.Completed += (s, e) => completedEvent.Set(); copier.Start(); completedEvent.WaitOne(); } /// <summary> /// The Async Copier class reads the input Stream Async and writes Synchronously /// </summary> public class AsyncStreamCopier { public event EventHandler Completed; private readonly Stream input; private readonly Stream output; private byte[] buffer = new byte[4096]; public AsyncStreamCopier(Stream input, Stream output) { this.input = input; this.output = output; } public void Start() { GetNextChunk(); } private void GetNextChunk() { input.BeginRead(buffer, 0, buffer.Length, InputReadComplete, null); } private void InputReadComplete(IAsyncResult ar) { // input read asynchronously completed int bytesRead = input.EndRead(ar); if (bytesRead == 0) { RaiseCompleted(); return; } // write synchronously output.Write(buffer, 0, bytesRead); // get next GetNextChunk(); } private void RaiseCompleted() { if (Completed != null) { Completed(this, EventArgs.Empty); } } } }