Естественно, когда один процесс работает, всем остальным следует подождать, пока он завершится. Если процесс доступен, он выполняется. Если нет, то отправляется ответ 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-вызова. Я ожидаю, что у меня будет два разных ответа: РАБОТА и ЗАНЯТ.
Однако я вижу, что второй запрос сначала ожидает завершения, а затем выполняется.
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
Что не так в моем понимании того, как это должно работать?
Обновить (слишком много комментариев не поощряется СО):
Мой код выглядит неуклюже, потому что это копия реального процесса. В «моем» приложении рабочий процесс — это основной процесс, который «любезно» запускает встроенный код C# в определенные моменты. Итак, я не могу запустить новую задачу для обработки запроса, и она должна быть асинхронной, поскольку рабочий процесс выполняет свою собственную работу и вызывает только подчиненный фрагмент кода для уведомления клиентов о доступности данных. Это асинхронно, потому что код вызывается и должен завершиться как можно скорее, иначе оно заблокирует главное приложение.
Я попробую добавить дополнительный поток с синхронным вызовом и посмотрю, как это повлияет на ситуацию.
В этом примере отладчик не используется, чтобы не мешать процессу в реальном времени и меткам времени, выводимым на консоль. Отладка — это здорово и необходимо, но в этом случае я стараюсь заменить ее выводом, чтобы избежать лишнего участника в сценарии синхронизации/ожидания.
Само приложение не является сильно нагруженным диалогом. 1-3 клиента редко запрашивают ответ у основного приложения. Протокол http используется для удобства, а не для тяжелых или частых разговоров. Похоже, что некоторые браузеры, такие как IE, работают нормально (разговор между Windows и Windows?), а некоторые, такие как Chrome (более независимые от системы), повторяют поведение моего приложения. Посмотрите на отметки времени: Chrome, IE, IE, Chrome и последний Chrome все еще перешли в рабочий процесс. Кстати, код меняется для каждого предложения разговора, и теперь новый запрос размещается сразу после получения предыдущего.
HttpListenerContext context = listener.EndGetContext(result);
listener.BeginGetContext(task, listener);

Кроме того, следуя рекомендациям, я заменил асинхронный вызов на синхронный, и результат остался прежним
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();
}
}
Подробнее здесь: https://stackoverflow.com/questions/349 ... tplistener