Patrick Skelton Ответов: 1

Это безопасно, чтобы получить доступ к коллекции concurrentqueue, используя итератор?


У меня есть встроенный в память "круговой" регистратор, который использует ConcurrentQueue внутренне.

Когда возникает ошибка, Я обращаюсь к содержимому журнала в памяти, чтобы дать дополнительный контекст сообщению об ошибке. Кажется, все работает нормально.

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

Основы моего кода заключаются в следующем:

public class Logger
{
    public void WriteLine( string text )
    {
		_textLines.Enqueue( text );
		if( _textLines.Count > _MaxLines )
			_textLines.TryDequeue( out string discardable );
    }

    public string[] WholeLog { get { return _textLines.ToArray(); } }

	private ConcurrentQueue<string> _textLines = new ConcurrentQueue<string>();

    private const uint _MaxLines = 100;
}


public class SomeClientCode
{
    public void PrintOutContentsOfMemoryLog
    {
        foreach( string logLine in _logger.WholeLog )
            Debug.Write( logLine );
    }

    private Logger _logger = new Logger();
}

Похоже ли это на то, что это может вызвать проблему?

Что я уже пробовал:

Я мог бы увеличить размер журнала в памяти до большого числа, а затем запустить другой поток и сделать несколько записей в узком цикле, пока первый поток пытается Распечатать журнал, но я еще не сделал этого теста, главным образом потому, что сначала хотел бы получить проверку здравомыслия от лучших программистов, чем я.

Я также знаю, что тест, подобный приведенному выше, не обязательно может показать проблему, если у меня есть фундаментальное непонимание этого. Я думаю, что на самом деле хочу сказать, что хотел бы чему-то научиться.

1 Ответов

Рейтинг:
5

Dave Kreskowiak

Они скрывают подобную информацию в интернете. документация[^]:

Цитата:
Перечисление представляет моментальный снимок содержимого очереди. Он не отражает какие-либо обновления коллекции после того, как был вызван метод getenumerator. Перечислитель можно безопасно использовать одновременно с чтением из очереди и записью в нее.

Перечислитель возвращает элементы коллекции в том порядке, в котором они были добавлены, то есть в порядке FIFO (first-in, first-out).


Patrick Skelton

Извините, я должен был проверить документацию. Я просто думал, что имею дело с фундаментальным принципом языка. Честно говоря, я удивлен, увидев такой четкий, по существу, ответ прямо там, в документации.

Я хотел чему-то научиться и научился. Урок таков: не верьте так мало в документацию.