Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.89/9: Рейтинг темы: голосов - 9, средняя оценка - 4.89
 Аватар для myjumanji
16 / 16 / 5
Регистрация: 18.05.2012
Сообщений: 39

Многопоточность, потокобезопасность. Простая программа по обработке .txt файлов

24.01.2014, 11:26. Показов 1834. Ответов 4
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день, коллеги.
Помогите исправить код.
Программа запрашивает количество потоков, делит их между текстовыми файлами исходя из определённой логики. Выводит информацию: номер потока, название файла, который обработался.

Во время дебага работает стабильно, во время исполнения без дебага - не так как задумывалось (поток с номером 0 почти никогда не выводится, часто дублируется информация "поток-файл"). Проблема с потокобезопасностью? Как наладить?
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
using System;
using System.Threading;
using System.IO;
 
class streams
{
    public static void StreamsStart(int threads, string[] directory)
    {
        Thread[] threadArray;
        int filesCount = directory.Length;
        //если количество файлов и потоков равное - каждому потоку по файлу
        if (threads == filesCount)
        {
            for (int i = 0; i < (threadArray = new Thread[threads]).Length; i++)
            {
                threadArray[i] = new Thread(new ThreadStart(() => { ReadFiles(i, directory[filesCount-1]); })) { IsBackground = true };
                threadArray[i].Start();
                filesCount--;
            }
        }
 
        //если количество файлов меньше, чем потоков - потоки делим между файлами, 
        //вначале раздаём всем файлам по 1 потоку
        //потом снова всем (или кому хватит) по 1 потоку и т.д. 
        else if (threads > filesCount)
        {
            for (int i = 0; i < (threadArray = new Thread[threads]).Length; i++)
            {
                if (filesCount < 1)
                {
                    filesCount = directory.Length;
                }
                threadArray[i] = new Thread(new ThreadStart(() => { ReadFiles(i, directory[filesCount-1]); })) { IsBackground = true };
                threadArray[i].Start();
                filesCount--;
 
            }
        }
 
        // если количество файлов больше, чем потоков - файлы делим между потоками, так: Например 26 файлов, 3 потока.
        // 26/3 = 8
        // и 2 в остатке.
        // 2 потока получают 9 файлов, 1 поток 8 файлов.     
        else
        {
            // целое
            int withoutResidue = filesCount / threads; 
            // остаток
            int residue = filesCount % threads; 
            
            for (int i = 0; i < (threadArray = new Thread[threads]).Length; i++)
            {
                threadArray[i] = new Thread(new ThreadStart(() => 
                {
                    //раздаём гарантировано всем потокам по целому набору файлов
                    for (int j = 0; j < withoutResidue; j++)
                    {
                        ReadFiles(i, directory[filesCount-1]);
                        filesCount--;
                    }
                    //если есть остаток, даём каждому потоку по 1 файлу, пока остаток не исчерпается
                    if (residue != 0)
                    {
                        ReadFiles(i, directory[filesCount-1]);
                        filesCount--;
                        residue--;
                    }
                }
                )) { IsBackground = true };           
               threadArray[i].Start(); 
            }
        }
    }
 
    private static readonly object syncRoot = new object();
 
    static void ReadFiles(int thread, string fileName)
    {
        lock (syncRoot)
        {
            using (FileStream file = File.Open(fileName, FileMode.Open))
            using (StreamReader stream = new StreamReader(file))
            {
                while (stream.Peek() >= 0)
                {
                    stream.ReadLine();
                }
                Console.WriteLine("Thread {0}, Filename {1}", thread, file.Name);
            }
        }
    }
}
 
 
class Program
{
    static void Main(string[] args)
    {
        string[] directory = Directory.GetFiles(@"C:\folder", "*.txt");
 
 
        Console.WriteLine("input number of threads");
        int threads = int.Parse(Console.ReadLine());
        streams.StreamsStart(threads, directory);
        // endofprogram
        Console.ReadKey();
    }
}
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
24.01.2014, 11:26
Ответы с готовыми решениями:

Потокобезопасность и многопоточность
Разбираюсь с принципами работы кэширования. есть LRU and LFU алгоритмы. Сейчас хочу сделать потокобезопасность. подскжате с чего здесь...

Есть ли простая программа для перевода pdf в txt
Интересно есть ли простая программа которая без лишних вопросов переведет документы pdf которые лежат в одной директории с прогой, в txt...

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

4
1195 / 588 / 88
Регистрация: 20.09.2012
Сообщений: 1,881
24.01.2014, 12:09
Цитата Сообщение от myjumanji Посмотреть сообщение
Как наладить?
1. Не использовать мутабельную переменную i в замыкании (new ThreadStart(() => ...) .
2. Пересмотреть логику раздачи содержимого string[] directory потокам.
2
 Аватар для myjumanji
16 / 16 / 5
Регистрация: 18.05.2012
Сообщений: 39
24.01.2014, 12:31  [ТС]
Цитата Сообщение от pycture Посмотреть сообщение
Не использовать мутабельную переменную i в замыкании (new ThreadStart(() => ...)
Почему?
Я хочу знать номер потока, который обрабатывает файл. Как я могу узнать этот номер иначе? Неужели эта переменная i может создать нестабильность? Каким образом?
0
 Аватар для Kruds
708 / 708 / 226
Регистрация: 04.03.2013
Сообщений: 1,384
24.01.2014, 13:18
Чуть переделал функцию, для простоты функция readfile заменена на консольный вывод.
Кликните здесь для просмотра всего текста
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public static void StreamsStart(int threads, string[] files)
{
    if (threads == files.Length)
    {
        for (int i = 0; i < threads; i++)
        {
            int index = i;
            Thread t = new Thread(new ThreadStart(() => Console.WriteLine(files[index]))) { IsBackground = true };
            t.Start();
        }
    }
 
    else if (threads > files.Length)
    {
        for (int i = 0; i < threads; i++)
        {
            int fileNumber = i > files.Length - 1 ? i % files.Length : i;
            Thread t = new Thread(new ThreadStart(() => Console.WriteLine(files[fileNumber]))) { IsBackground = true };
            t.Start();
        }
    }
 
    else
    {
        int range = files.Length / threads;
        for (int i = 0; i < threads; i++)
        {
            int from = i * range,
                to = i == threads - 1 ? files.Length : from + range;
            Thread t = new Thread(new ThreadStart(() => { for (int j = from; j < to; Console.WriteLine(files[j++])); })) { IsBackground = true };
            t.Start();
        }
    }
}

Кстати говоря, про распараллеливание есть неплохая статья, вот.
pycture, растолкуйте пожалуйста. Когда переменная i используется в лямбда выражении, понятно что происходит лишь описание метода, и подставлено будет значение актуальное на момент вызова. Исключение IndexOutOfRange можно словить потому что поток, вообще говоря, может быть запущен и после выхода из цикла?
1
1195 / 588 / 88
Регистрация: 20.09.2012
Сообщений: 1,881
24.01.2014, 13:30
Лучший ответ Сообщение было отмечено myjumanji как решение

Решение

Цитата Сообщение от myjumanji Посмотреть сообщение
Почему?
Потому как нельзя. Неразгребешь потом, тем более в многопоточности, наглядный пример этот топик. В F# вообще на уровне компилятора запрет, что б неповадно было.
Цитата Сообщение от myjumanji Посмотреть сообщение
Как я могу узнать этот номер иначе?
C#
1
2
3
threadArray[i] = new Thread(new ParameterizedThreadStart(k =>
..............
threadArray[i].Start(i);
Цитата Сообщение от myjumanji Посмотреть сообщение
Неужели эта переменная i может создать нестабильность? Каким образом?
Если кратко, то большинство ReadFiles(i, directory[filesCount-1]); происходит когда цикл for давно завершил свою работу и переменная i стала = threads. Соотвественно только это значание и используется.

Добавлено через 11 минут
Цитата Сообщение от Kruds Посмотреть сообщение
pycture, растолкуйте пожалуйста
Показываю на кошках.
Неправильный вариант с мутабельной переменной в замыкании http://ideone.com/886Egd
Вариант с параметром http://ideone.com/rUk14U
2
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
24.01.2014, 13:30
Помогаю со студенческими работами здесь

Простая программа обмена файлов
привет всем. можете дать или написать исходники программ передающих файлы по сети? самые простые.. для изучения.. буду благодарен)

Простая программа для просмотра списка файлов
Доброго времени суток! Обращаюсь к вам как специалистам программистам, и профессионалам своего дела. Так как таковым не являюсь, и...

Создать новый файл qa.txt, который будет содержать строки с вопросами и ответами из файлов q.txt и a.txt.
В текстовом редакторе создать два текстовых файла q.txt и a.txt, которые соответственно содержат вопросы и ответы на их. Создать новый файл...

Переписать все числа из файлов 1.txt и 2.txt в файл 3.txt
Здравствуйте! Нужна помощь. Есть два текстовых файла 1.txt и 2.txt в них есть числа. реализовать консольное приложение которое...

Обработка файлов с созданием и использованием файла со списком имён файлов, исключаемых при данной обработке
Эх, чтобы я без вас делал то ;) Доброго времени суток! Задача сценария: просматривать файлы в текущей директории и если их нету в...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Новые блоги и статьи
Как я обхитрил таблицу Word
Alexander-7 21.03.2026
Когда мигает курсор у внешнего края таблицы, и нам надо перейти на новую строку, а при нажатии Enter создается новый ряд таблицы с ячейками, то мы вместо нервных нажатий Энтеров мы пишем любые буквы. . .
Krabik - рыболовный бот для WoW 3.3.5a
AmbA 21.03.2026
без регистрации и смс. Это не торговля, приложение не содержит рекламы. Выполняет свою непосредственную задачу - автоматизацию рыбалки в WoW - и ничего более. Однако если админы будут против -. . .
Программный отбор значений справочника
Maks 21.03.2026
Установка программного отбора значений справочника "Сотрудники" из модуля формы документа. В качестве фильтра для отбора служит предопределенное значение перечислений. Процедура. . .
Переходник USB-CAN-GPIO
Eddy_Em 20.03.2026
Достаточно давно на работе возникла необходимость в переходнике CAN-USB с гальваноразвязкой, оный и был разработан. Однако, все меня терзала совесть, что аж 48-ногий МК используется так тупо: просто. . .
Оттенки серого
Argus19 18.03.2026
Оттенки серого Нашёл в интернете 3 прекрасных модуля: Модуль класса открытия диалога открытия/ сохранения файла на Win32 API; Модуль класса быстрого перекодирования цветного изображения в оттенки. . .
SDL3 для Desktop (MinGW): Рисуем цветные прямоугольники с помощью рисовальщика SDL3 на Си и C++
8Observer8 17.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-rectangles-sdl3-c. zip finish-rectangles-sdl3-cpp. zip
Символические и жёсткие ссылки в Linux.
algri14 15.03.2026
Существует два типа ссылок — символические и жёсткие. Ссылка в Linux — это запись в каталоге, которая может указывать либо на inode «файла-ИСТОЧНИКА», тогда это будет «жёсткая ссылка» (hard link),. . .
[Owen Logic] Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ФедосеевПавел 14.03.2026
Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора ВВЕДЕНИЕ Выполняя задание на управление насосной группой заполнения резервуара,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru