Надеюсь, что кто-то может помочь мне правильно спроектировать это.
В моем коде TCP у меня есть функция SendMessage (), которая пытается записать на провод. Я пытаюсь спроектировать вызов так, чтобы он перешел к модели производителя / потребителя, если происходит много одновременных запросов, но в то же время остается однопоточным, если нет одновременных запросов (для максимальной производительности).
Я борюсь за то, как спроектировать это без условий гонки, потому что нет способа перемещать блокировки между потоками.
То, что у меня есть, что-то вроде (псевдокодирование):
SendMessage(msg) {
if(Monitor.TryEnter(wirelock,200)) {
try{
sendBytes(msg);
}
finally {
Monitor.Exit...
}
}
else {
_SomeThreadSafeQueue.add(msg)
Monitor.TryEnter(consumerlock,..
Task.Factory.New(ConsumerThreadMethod....
}
}
ConsumerThreadMethod() {
lock (wirelock) {
while(therearemessagesinthequeue)
sendBytes...
}
}
Какие-нибудь очевидные условия гонки?
РЕДАКТИРОВАТЬ: нашел недостаток в последнем. Как насчет этого вместо этого?
SendMessage(msg) {
if(Monitor.TryEnter(wirelock)) {
try{
sendBytes(msg);
}
finally {
Monitor.Exit...
}
}
else {
_SomeThreadSafeQueue.add(msg)
if (Interlocked.Increment(ref _threadcounter) == 1)
{
Task.Factory.StartNew(() => ConsumerThreadMethod());
}
else
{
Interlocked.Decrement(ref _threadcounter);
}
}
}
ConsumerThreadMethod() {
while(therearemessagesinthequeue)
lock (wirelock) {
sendBytes...
}
}
Interlocked.Decrement(ref _threadcounter);
}
Таким образом, в основном используется блокированный счетчик как способ создания только одного потока (при необходимости)