私は長い時間を実行するシングルスレッドプロセスを持っています。私はこのプロセスを実行するために複数のユーザーにアクセスする必要があり、私は呼び出しを管理するためにhttpプロトコルを選択します。HttpListenerのマルチスレッド応答
もちろん、1つのプロセスが動作しているときは、他のすべてのプロセスが完了するまで待つべきです。プロセスが利用可能であれば、それは実行されます。そうでない場合は、BUSY応答が送信されます。
using System;
using System.Net;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace simplehttp
{
class Program
{
private static System.AsyncCallback task;
private static System.Threading.ManualResetEvent mre = new System.Threading.ManualResetEvent(false);// Notifies one or more waiting threads that an event has occurred.
private static HttpListenerContext workingContext = null;
public static bool isBackgroundWorking()
{
return mre.WaitOne(0);
}
static void Main(string[] args)
{
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
while (true)
{
Console.WriteLine(" waitOne " + isBackgroundWorking());
mre.WaitOne(); // Blocks the current thread until the current WaitHandle receives a signal.
Console.WriteLine(" do job" + " [" + Thread.CurrentThread.Name + ":" + Thread.CurrentThread.ManagedThreadId + " ]\n");
HttpListenerRequest request = workingContext.Request;
HttpListenerResponse response = workingContext.Response;
string responseString = "WORK " + DateTime.Now ;
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
System.IO.Stream output = response.OutputStream;
Thread.Sleep(10000);
output.Write(buffer, 0, buffer.Length);
output.Close();
Console.WriteLine(" " + responseString + "\t" + DateTime.Now);
workingContext = null;
mre.Reset(); // Sets the state of the event to nonsignaled, causing threads to block.
}
}).Start();
// Create a listener.
HttpListener listener = new HttpListener();
listener.Prefixes.Add("http://localhost:6789/index/");
listener.Start();
Console.WriteLine("Listening..." + " [" + Thread.CurrentThread.Name + ":" + Thread.CurrentThread.ManagedThreadId + " ]\n");
task = new AsyncCallback(ListenerCallback);
IAsyncResult resultM = listener.BeginGetContext(task,listener);
Console.WriteLine("Waiting for request to be processed asyncronously.");
Console.ReadKey();
Console.WriteLine("Request processed asyncronously.");
listener.Close();
}
private static void ListenerCallback(IAsyncResult result)
{
HttpListener listener = (HttpListener) result.AsyncState;
//If not listening return immediately as this method is called one last time after Close()
if (!listener.IsListening)
return;
HttpListenerContext context = listener.EndGetContext(result);
listener.BeginGetContext(task, listener);
if (workingContext == null && !isBackgroundWorking())
{
// Background work
workingContext = context;
mre.Set(); //Sets the state of the event to signaled, allowing one or more waiting threads to proceed.
}
else
{
HttpListenerRequest request = context.Request;
HttpListenerResponse response = context.Response;
string responseString = "BUSY "+ DateTime.Now + " [" + Thread.CurrentThread.Name + ":" + Thread.CurrentThread.ManagedThreadId;
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
System.IO.Stream output = response.OutputStream;
output.Write(buffer, 0, buffer.Length);
output.Close();
Console.WriteLine(responseString + "\t" + DateTime.Now);
}
}
}
}
私は2つのHTTP呼び出しを行うテストするには:ここでは
は実装です。私は2つの異なる答えがあると思うWORKとBUSY。 しかし、2番目のリクエストが最初に終了してから実行されるのを待っています。
waitOne False
Listening... [:10 ]
Waiting for request to be processed asyncronously.
do job [:11 ]
WORK 1/24/2016 10:34:01 AM 1/24/2016 10:34:11 AM
waitOne False
do job [:11 ]
WORK 1/24/2016 10:34:11 AM 1/24/2016 10:34:21 AM
waitOne False
どうすればうまくいくはずですか?
更新(あまりにも多くのコメントは、SOによってecouragedされていません): 私のコードは、実際のプロセスの複製ですので、厄介なように見えます。 「私の」アプリケーションでは、作業プロセスは、特定の瞬間に埋め込まれたC#コードを実行する「礼儀」を持っている主要なプロセスです。したがって、私は要求を処理するための新しいタスクを実行することはできませんし、作業プロセスが独自の仕事をし、データが利用可能であるときにクライアントに通知するためにスレーブコードを呼び出すだけなので、非同期的でなければなりません。コードが呼び出され、できるだけ早く終了するか、マスターアプリケーションをブロックするため、非同期です。 私は同期呼び出しでスレッドを追加しようとすると、状況に影響を与えるホット参照してください。
この例では、コンソールに出力されたリアルタイムのプロセスとタイムスタンプを妨害しないためにデバッガは使用されません。デバッグはすばらしく、必要ですが、この場合は、同期/待機のシナリオで余分なアクタを避けるために出力に置き換えようとします。
アプリケーション自体は負荷の高い会話ではありません。 1-3人のクライアントは、メインアプリケーションに回答することはめったにありません。 httpプロトコルは、重い、またはしばしば会話のためではなく便宜のために使用されます。 IEのようないくつかのブラウザ(WindowsからWindowsへの会話?)とChrome(よりシステムに依存しないもの)のようなものは、私のアプリケーションの動作を複製するように見えます。タイムスタンプ、Chrome、IE、IE、Chromeを見て、最後のChromeはまだWORKプロセスに行きました。ところで、会話の提案につきコードが変更され、新しいリクエストは直前のリクエストを検索した直後に配置されます。
HttpListenerContext context = listener.EndGetContext(result);
listener.BeginGetContext(task, listener);
また、提案以下、私は完全に読み、そのコードを理解していないsyncroniuosにasyncroniousコールを変更し、結果はまだ同じ
private static void ListenerCallback(IAsyncResult result)
{
HttpListener listener = (HttpListener) result.AsyncState;
//If not listening return immediately as this method is called one last time after Close()
if (!listener.IsListening)
return;
HttpListenerContext context = listener.EndGetContext(result);
while (true)
{
if (workingContext == null && !isBackgroundWorking())
{
// Background work
workingContext = context;
mre.Set(); //Sets the state of the event to signaled, allowing one or more waiting threads to proceed.
}
else
{
HttpListenerRequest request = context.Request;
HttpListenerResponse response = context.Response;
string responseString = "BUSY " + DateTime.Now + " [" + Thread.CurrentThread.Name + ":" +
Thread.CurrentThread.ManagedThreadId;
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
System.IO.Stream output = response.OutputStream;
output.Write(buffer, 0, buffer.Length);
output.Close();
Console.WriteLine(responseString + "\t" + DateTime.Now);
}
context=listener.GetContext();
}
}
これは重要な情報です。だからあなたが投稿したコードについては何が真実で、何が虚偽ですか?私はどのような変化を提案でき、どこを見ていくのか分からない。 – usr
EndGCの直後にBeginGetContextを呼び出す必要がある理由が1つあります。コードは今のところ、間に多くの作業が行われています。 – usr
Btw、デバッガを使って何が起こったのか確認しましたか? – usr