Поток безопасный StreamWriter C # как это сделать? 1 - PullRequest
5 голосов
/ 28 августа 2010

Каков наилучший способ создания программы, которая является поточно-ориентированной, с точки зрения необходимости записи двойных значений в файл. Если функция, которая сохраняет значения через streamwriter, вызывается несколькими потоками? Какой лучший способ сделать это?


Код из комментария:

    static void Main()
    {
        List<double> Values = new List<double>();
        StreamWriter writer = new StreamWriter("test.out");

        for (int i = 0; i < 1000; i++) Values.Add(i);

        foreach (double V in Values)
        {
            ThreadPool.QueueUserWorkItem(delegate(object state) { SaveValues(writer, V); }, V);
        }
    }

    static void SaveValues(StreamWriter writer, double Value)
    {
        lock (writer) writer.WriteLine(Value);
    } 

Ответы [ 5 ]

7 голосов
/ 28 августа 2010

TextWriter.Synchronized

Создает потокобезопасную оболочку вокруг указанного TextWriter.ll пишет в возвращаемую оболочку будет потокобезопасным.

5 голосов
/ 28 августа 2010

Редактировать, после расшифровки кода в вашем комментарии

Ваша проблема не с блокировкой или потоками, а с захватом переменной цикла. Это классическая проблема, все ваши потоки запускаются с «захватом» одной переменной V, и к тому моменту, когда потоки будут выполнены, ее конечное значение достигнет 999. За исключением, может быть, первых нескольких рабочих элементов.

Итак, вместо:

foreach (double V in Values)
{  
   ThreadPool.QueueUserWorkItem(delegate(object state) 
        { SaveValues(writer, V); }, V); // use of captured V: almost always 999
}

использование

foreach (double V in Values)
{
    double W = V;
    ThreadPool.QueueUserWorkItem(delegate(object state)
       { SaveValues(writer, W); }, V);
}

или, более кратко,

foreach (double V in Values)
{
    double W = V;
    ThreadPool.QueueUserWorkItem((state) => SaveValues(writer, W));
}

В качестве варианта ответа @ Matti рекомендуется заблокировать отдельный простой объект. Это снижает риск того, что что-то еще блокируется на том же объекте (например, сам код StreamWriter).

private StreamWriter writer = ...;         
private Object writerLock = new Object();  // don't expose through a property 
// or any other way

lock (writerLock)
{
    writer.Write(...);
}

Но то, как вы настроили метод SaveValues(StreamWriter writer, ...), делает его немного сложнее. Лучше иметь объект, где writer и writerLock являются частными членами.

3 голосов
/ 28 августа 2010

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

3 голосов
/ 28 августа 2010

Заблокируйте его при доступе к нему.

lock (myStreamWriter) {
    myStreamWriter.Write(...);
}

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

2 голосов
/ 28 августа 2010

Вы можете синхронизироваться с блокировкой на StreamWriter (или объектом синхронизации, который используется, когда потоки хотят получить доступ к StreamWriter).Однако, когда несколько потоков пытаются записать, только один сможет продолжить.

Если это проблема, вы можете вместо этого реализовать очередь и добавить поток записи.Поток записи будет отключен и запишет в StreamWriter.Другие потоки будут ставить элементы в очередь вместо прямой записи элементов.

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

Редактировать

Похоже, Стивен Клири имеет ссылку наСуществующий класс .NET, который вы можете использовать для реализации очереди.Я оставлю свой ответ, так как он объясняет, почему вы хотите сделать производителя / потребителя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...