Извините, ничего не найдено.

Не расстраивайся! Лучше выпей чайку!
Регистрация
Справка
Календарь

Вернуться   forum.boolean.name > Программирование игр для компьютеров > С#

С# Средство разработки на платформе .Net

Ответ
 
Опции темы
Старый 28.02.2015, 20:21   #1
pax
Unity/C# кодер
 
Аватар для pax
 
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,568
Написано 3,006 полезных сообщений
(для 5,323 пользователей)
Асинхронная очередь

Помогите сделать асинхронную очередь. У меня что-то не особо получается.

private objject _thisLocker = new object();
        private 
IAsyncResult _writingAR;
        
readonly Queue<NetMessage_sendQueue = new Queue<NetMessage>();

        
// посылаю сообщение
        
public void Send(NetMessage msg)
        {
            if (
msg.sended) throw new InvalidOperationException("Message already sended!");

            
msg.sended true;

            
// добавляю сообщение в очередь
            
Enqueue(msg);
        }

        
// добавление в очередь
        
internal void Enqueue(NetMessage msg)
        {
            
lock (_thisLocker// лок, чтобы никто сюда не вошел
            
{
                
_sendQueue.Enqueue(msg);

                
// если не равно null, то идет отправка
                
if (_writingAR != null)
                {
                    return;
                }
                
                
// начинаю отправку, если в очереди есть сообщения
                
if (_sendQueue.Count 0)
                {
                    var 
nextMessage _sendQueue.Dequeue();
                    
// ?????????????????? почему в данный момент _writingAR != null ???????????????????
                    
_writingAR NetworkStream.BeginWrite(nextMessage.data0nextMessage.Size NetMessage.HeaderSizeOnEndWritenextMessage);
                }
            }
        }

        
// завершение отправки
        
private void OnEndWrite(IAsyncResult ar)
        {
            
NetworkStream.EndWrite(ar);

            
lock (_thisLocker// лок, чтобы никто сюда не вошел
            
{
                
// если в очереди есть еще сообщения, начинаю отправку следующих сообщений, если они есть
                
if (_sendQueue.Count 0)
                {
                    var 
nextMessage _sendQueue.Dequeue();
                    
_writingAR NetworkStream.BeginWrite(nextMessage.data0nextMessage.Size NetMessage.HeaderSizeOnEndWritenextMessage);
                }
                else
                {
                    
_writingAR null;
                }
            }
        } 
Пробовал лочить, но не получается. Отправка сообщений происходит не по порядку, т.е. несколько отправок одновременно.
__________________
Blitz3d to Unity Wiki
(Offline)
 
Ответить с цитированием
Старый 01.03.2015, 11:54   #2
h1dd3n
Бывалый
 
Аватар для h1dd3n
 
Регистрация: 19.06.2008
Сообщений: 679
Написано 264 полезных сообщений
(для 450 пользователей)
Ответ: Асинхронная очередь

Неправильный подход у тебя.

Тебе нужна очередь в которую сообщение будет при отправке добавляться, и отдельный асинхронный воркер который будет забирать из очереди и отправлять.

И отдельный асинхронный воркер, проще всего в отдельном потоке запилить.



ConcurrentQueue


Где-то в коде:
private void Initialize() {
	this._queue = new ConcurrentQueue<NetMessage>();

	var asyncWorker = new Thread(SomeWorker);
	asyncWorker.Start();
}
public void Send(NetMessage msg) {
	if (msg.sended) throw new InvalidOperationException("Message already sended!");

	msg.sended = true;

	this._queue.Enqueue(msg);
}
private void SomeWorker() {
	while (true) {
		NetMessage msg;
		while (!this._queue.TryDequeue(out msg)) {
			
		}

                NetworkStream.Write(nextMessage.data, 0, nextMessage.Size + NetMessage.HeaderSize);
	}
}
Кстати, какая у тебя целевая платформа ? Если .NET 4.5, то советую вместо BeginWrite/EndWrite использовать await WriteAsync.
__________________

Последний раз редактировалось h1dd3n, 01.03.2015 в 13:03.
(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
pax (01.03.2015)
Старый 01.03.2015, 13:13   #3
pax
Unity/C# кодер
 
Аватар для pax
 
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,568
Написано 3,006 полезных сообщений
(для 5,323 пользователей)
Ответ: Асинхронная очередь

Мне вроде удалось решить мою задачу с помощью Interlocked.Exchange
private int _writing;
        
readonly Queue<NetMessage_sendQueue = new Queue<NetMessage>();

        
// посылаю сообщение
        
public void Send(NetMessage msg)
        {
            if (
msg.sended) throw new InvalidOperationException("Message already sended!");

            
msg.sended true;

            
// добавляю сообщение в очередь
            
Enqueue(msg);

        }

        
// добавление в очередь
        
internal void Enqueue(NetMessage msg)
        {
            
lock (_sendQueue)
            {
                
_sendQueue.Enqueue(msg);
            }

            
SendNext();
        }

        private 
void OnEndWrite(IAsyncResult ar)
        {
            
NetworkStream.EndWrite(ar);
            
Interlocked.Exchange(ref _writing0);
            
SendNext();
        }

        
byte[] _sendBuffer = new byte[1024];
        
readonly List<NetMessage_messagesToSend = new List<NetMessage>();

        
internal bool SendNext()
        {
            var 
current Interlocked.Exchange(ref _writing1);

            if (
current == 0// если нет отправки, отправляю
            
{
                
int countBytesToSend 0;
                
int countMesagesToSend 0;

                
lock (_sendQueue)
                {
                    
_messagesToSend.Clear();

                    while (
_sendQueue.Count 0)
                    {
                        var 
msg _sendQueue.Dequeue();
                        
_messagesToSend.Add(msg);
                        
countMesagesToSend++;
                        
countBytesToSend += msg.SizeToSend;
                        if (
countBytesToSend 1024 32)
                        {
                            break;
                        }
                    }
                }


                if (
countBytesToSend 0)
                {
                    if (
_sendBuffer.Length countBytesToSend)
                    {
                        Array.
Resize(ref _sendBuffercountBytesToSend);
                    }

                    var 
pos 0;

                    for (
int i 0_messagesToSend.Counti++)
                    {
                        var 
msg _messagesToSend[i];
                        Array.
Copy(msg.data0_sendBufferposmsg.SizeToSend);
                        
pos += msg.SizeToSend;
                    }
                    
NetworkStream.BeginWrite(_sendBuffer0posOnEndWritenull);
                }
                else
                {
                    
// нечего слать, значит ничего не отправляю и отправки нет
                    
Interlocked.Exchange(ref _writing0);
                }
            }

            return 
false;
        } 
__________________
Blitz3d to Unity Wiki
(Offline)
 
Ответить с цитированием
Эти 3 пользователя(ей) сказали Спасибо pax за это полезное сообщение:
Igor (01.03.2015), Mr_F_ (01.03.2015), St_AnGer (02.03.2015)
Ответ


Опции темы

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


Часовой пояс GMT +4, время: 15:39.


vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot
Style crйe par Allan - vBulletin-Ressources.com