Вы не должны жить с тем расширением, если можно установить фильтр ISAPI на сервере.
В основном Вы направляете подобранные URL к {контроллер} .mvc разнообразие, затем в ASP.NET, Вы переписываете этот URL для удаления .mvc - выполнение этого, Вы не должны определять дополнительные маршруты или представлять .mvc Вашим пользователям.
я записал об этом здесь: http://www.flux88.com/UsingASPNETMVCOnIIS6WithoutTheMVCExtension.aspx
и Steve Sanderson имеет хорошее сообщение здесь также: http://blog.codeville.net/2008/07/04/options-for-deploying-aspnet-mvc-to-iis-6/
Вроде должно работать. Производители-потребители не должны сильно меняться в случае единственного потребителя. Маленькие придирки:
получение блокировки может оказаться дорогостоящей операцией (как говорит @Vitaliy Lipchinsky). Я бы рекомендовал сравнить ваш регистратор с наивным "сквозным" регистратором и регистратором с использованием взаимосвязанных операций. Другой альтернативой может быть замена существующей очереди пустой в GetLog
и немедленный выход из критического раздела. Таким образом, ни один из производителей не будет заблокирован длительными операциями с потребителями.
Сделайте LogObj ссылочным типом (классом). Нет смысла делать его структурированным, так как вы все равно его упаковываете. или иначе сделайте поле _queue
типом LogObj []
(в любом случае это лучше).
сделайте фон вашего потока так, чтобы он не препятствовал закрытию вашей программы, если не будет вызвана Stop
.
Очистите ваш TextWriter
. В противном случае вы рискуете потерять даже те записи, которые уместились в очереди (10 элементов - это немного ИМХО).
Реализуйте IDisposable и / или финализатор. Вашему регистратору принадлежит поток и средство записи текста, и они должны быть освобождены (и очищены - см. Выше).
Привет. Бегло взглянул, и хотя он кажется потокобезопасным, я не считаю, что он особенно оптимален. Я бы предложил решение в этом направлении
ПРИМЕЧАНИЕ: просто прочтите другие ответы. Далее следует довольно оптимальное, оптимистичное решение блокировки, основанное на вашем собственном. Основные отличия заключаются в блокировке внутреннего класса, минимизации «критических секций» и обеспечении плавного завершения потока. Если вы хотите полностью избежать блокировки, вы можете попробовать некоторые из этих непостоянных «неблокирующих» связанных списков, как предлагает @Vitaliy Lipchinsky.
using System.Collections.Generic;
using System.Linq;
using System.Threading;
...
public class Logger
{
// BEST PRACTICE: private synchronization object.
// lock on _syncRoot - you should have one for each critical
// section - to avoid locking on public 'this' instance
private readonly object _syncRoot = new object ();
// synchronization device for stopping our log thread.
// initialized to unsignaled state - when set to signaled
// we stop!
private readonly AutoResetEvent _isStopping =
new AutoResetEvent (false);
// use a Queue<>, cleaner and less error prone than
// manipulating an array. btw, check your indexing
// on your array queue, while starvation will not
// occur in your full pass, ordering is not preserved
private readonly Queue<LogObj> _queue = new Queue<LogObj>();
...
public void Log (string message)
{
// you want to lock ONLY when absolutely necessary
// which in this case is accessing the ONE resource
// of _queue.
lock (_syncRoot)
{
_queue.Enqueue (new LogObj (DateTime.Now, message));
}
}
public void GetLog ()
{
// while not stopping
//
// NOTE: _loggerThread is polling. to increase poll
// interval, increase wait period. for a more event
// driven approach, consider using another
// AutoResetEvent at end of loop, and signal it
// from Log() method above
for (; !_isStopping.WaitOne(1); )
{
List<LogObj> logs = null;
// again lock ONLY when you need to. because our log
// operations may be time-intensive, we do not want
// to block pessimistically. what we really want is
// to dequeue all available messages and release the
// shared resource.
lock (_syncRoot)
{
// copy messages for local scope processing!
//
// NOTE: .Net3.5 extension method. if not available
// logs = new List<LogObj> (_queue);
logs = _queue.ToList ();
// clear the queue for new messages
_queue.Clear ();
// release!
}
foreach (LogObj log in logs)
{
// do your thang
...
}
}
}
}
...
public void Stop ()
{
// graceful thread termination. give threads a chance!
_isStopping.Set ();
_loggerThread.Join (100);
if (_loggerThread.IsAlive)
{
_loggerThread.Abort ();
}
_loggerThread = null;
}
Я просто провожу здесь мысленный эксперимент, так как у меня нет времени на самом деле сейчас попробовать код, но я думаю, что вы можете сделать это вообще без блокировок, если будете изобретательны.
Пусть ваш класс ведения журнала содержит метод, который выделяет очередь и семафор каждый раз, когда он вызывается (и еще один, который освобождает очередь и семафор, когда поток завершен). Потоки, которые хотят вести журнал, будут вызывать этот метод при запуске. Когда они хотят войти, они помещают сообщение в свою очередь и устанавливают семафор. У потока регистратора есть большой цикл, который проходит через очереди и проверяет связанные семафоры. Если семафор, связанный с очередью, больше нуля, то очередь отключается, а семафор уменьшается.
Поскольку вы не пытаетесь вытолкнуть вещи из очереди до тех пор, пока семафор не будет установлен, и вы не устанавливая семафор до тех пор, пока вы не поместите вещи в очередь, я думаю это будет безопасно. Согласно документации MSDN для класса очереди, если вы перечисляете очередь, а другой поток изменяет коллекцию, возникает исключение. Поймайте это исключение, и все будет хорошо.
затем очередь удаляется, а семафор уменьшается.Поскольку вы не пытаетесь вытолкнуть объекты из очереди до тех пор, пока семафор не будет установлен, и вы не устанавливаете семафор до тех пор, пока не поместите объекты в очередь, я думаю это будет безопасно. Согласно документации MSDN для класса очереди, если вы перечисляете очередь, а другой поток изменяет коллекцию, возникает исключение. Поймайте это исключение, и все будет хорошо.
затем очередь удаляется, а семафор уменьшается.Поскольку вы не пытаетесь вытолкнуть объекты из очереди до тех пор, пока семафор не будет установлен, и вы не устанавливаете семафор до тех пор, пока не поместите объекты в очередь, я думаю это будет безопасно. Согласно документации MSDN для класса очереди, если вы перечисляете очередь, а другой поток изменяет коллекцию, возникает исключение. Поймайте это исключение, и все будет хорошо.
если вы перечисляете очередь, а другой поток изменяет коллекцию, генерируется исключение. Поймайте это исключение, и все будет хорошо. если вы перечисляете очередь, а другой поток изменяет коллекцию, генерируется исключение. Поймайте это исключение, и все будет хорошо.Фактически, вы вводите блокировку здесь. У вас есть блокировка при отправке записи журнала в очередь (метод журнала): если 10 потоков одновременно поместили 10 элементов в очередь и разбудили поток регистратора, то 11-й поток будет ждать, пока поток регистратора не зарегистрирует все элементы ...
Если вы хотите что-то действительно масштабируемое - реализуйте безблокировочную очередь (пример ниже). С механизмом синхронизации очереди без блокировки будет действительно сразу (вы даже можете использовать единственный дескриптор ожидания для уведомлений).
Если вам не удастся найти реализацию очереди без блокировки в Интернете, вот идея, как это сделать этот: Используйте связанный список для реализации. Каждый узел в связанном списке содержит значение и временную ссылку на следующий узел. поэтому для операций постановки в очередь и удаления из очереди вы можете использовать метод Interlocked.CompareExchange. Надеюсь, идея понятна. Если нет - дайте мне знать, и я предоставлю более подробную информацию.