Я новичок в программировании, многопоточности и поточно-безопасной синхронизации в целом, много читал и искал, нашел десятки похожих вопросов - однако не смог найти ничего, что могло бы мне помочь в итоге - или ни моего отсутствиязнание темы не позволило мне заметить / понять ответ.
Я создал класс с 3 полями данных (string, int, double) и 1 method (будетиспользоваться для вычисления нового значения - которое позже будет сравниваться с выбранными критериями фильтрации).
Затем я хочу, чтобы мой основной поток выполнял действия в следующем порядке:
- Считывает данные (3 файла) к выбранной структуре данных. - давайте проигнорируем эти
- Запускает выбранное количество потоков (2 <= x <= n / 4, n - количество записей в файле), которые будут принимать записи, выполнить метод <strong> для них, и если результат соответствует критериям - запись будет записана в структуру данных результатов .
- В структуру данных, которая использовалась для передачи данных через потоки, вставляет всечтение данных.
- Ожидание завершения всех потоков.
- Запись данных из структуры результатов в файл. - давайте проигнорируем эти
Требования к потокам:
- Когда все данные обработаны, потоки автоматически завершают работу. Пока работает хотя бы один поток, основной поток ожидает его завершения.
- Данные в потоки передаются через синхронизированную структуру данных: монитор. Мне нужно реализовать его как класс или структуру, которая содержит методы добавления и удаления.
- Данные внутри класса монитора сохраняются в массиве (arr.size <= все размеры данных / 2) </li>
- Если предпринята попытка чтения / удаления с монитора, когда внутренний массивпусто или запись / добавление, когда внутренний массив заполнен, поток заблокирован - через условную синхронизацию потоки выполняются только после того, как какое-то условие выполнено, я полагаю. (Используются методы lock, unlock, Monitor.Wait Pulse и PulseAll).
- Структура данных результата такая же, как и исходная структура данных, за исключением отсутствия фиксированного размера массива. Данные в структуру результата должны быть добавлены по порядку.
На данный момент у меня есть это (псевдо-иш):
Также я пытался искать разныереализации того, о чем я говорю, и до сих пор с треском проваливались, сейчас 7 часов утра - поэтому код беспорядок, я извиняюсь за это
class Computer // 3 field class.
{
public string _model { get; set; }
public int _ram { get; set; }
public double _screen { get; set; }
double methodForFilterValue(Computer computer)
{
return computer._screen + computer._ram;
}
}
class Computers // Monitor class.
{
Computer[] _computers; // array of computers - buffer.
int _bufferHead { get; set; } // circular buffer properties.
int _counter { get; set; }
int _bufferTail { get; set; }
int _length { get; private set; }
private readonly object _locker = new Object();
Computers (int length)
{
_bufferHead = _bufferTail = -1;
_length = length;
_computers = new Computer[length];
_counter = 0;
}
Computers(Computer[] computers)
{
_length = computers.Length;
_computers = computers;
_bufferHead = 0;
_bufferTail = _length - 1;
_counter = computers.ToList().Count;
}
Add(Computer computer)
{
lock (_locker)
{
if((_bufferHead == 0 && _bufferTail == _length - 1) || (_bufferTail +1 == _bufferHead))
{
//means Empty.
return;
}
else
{
if (_bufferTail == _length - 1)
_bufferTail = 0;
else
_bufferTail++;
_computers[_bufferTail] = computer;
_counter++;
}
if (_bufferHead == -1)
_bufferHead = 0;
}
}
Remove()
{
lock (_locker){} -- not implemented yet.
}
}
class ResultStructure // Result class - for filtered records, printing to file.
{
public Computer[] _resultComputers;
public int _capacity { get; set; }
public int _counter { get; set; }
private readonly object _locker = new Object();
private const int INITIAL_BUFFER_SIZE = 10;
public ResultStructure()
{
_resultComputers = new Computer[INITIAL_BUFFER_SIZE];
_capacity = INITIAL_BUFFER_SIZE;
_counter = 0;
}
public ResultStructure(int length)
{
_resultComputers = new Computer[length];
_capacity = length;
_counter = 0;
}
public void AddSorted(Computer computer)
{
-- yet to be implemented also.
}
}
class Program
{
static void Main(string[] args)
{
int size = 90; // single file size: 30 lines.
string path = AppDomain.CurrentDomain.BaseDirectory;
string[] filePaths = Directory.GetFiles(file_*.json");
int selectedCriteria = 20; // each computer's methodForFilterValue() will have to result in a higher value than 20 for it to be added to resultStructure.
Computers allComputers = new Computers(size/2);
Computers[] computers = new Computers[filePaths.Length];
ResultStructure result = new ResultStructure(size);
**//STEPS:**
**//1. Data read.**
for (int i = 0; i < filePaths.Length; i++)
{
computers[i] = ReadJson(filePaths[i]);
}
**//2. ??? - Need explanation on this part.**
**//Basically this part about: iterating through each record in computers[i] - calling methodForFilterValue() function, checking if the result of that function is > 20 and if yes, add record to result._resultComputers array. Items should be added while leaving the array sorted. "AddSorted()"**
**//3. Run threads - addAll items to the same data struct.**
var threadsAdd = Enumerable.Range(0, filePaths.Length).Select(i => new Thread(() =>
{
for (int j = 0; j < computers[i]._computers.Length; j++)
{
allComputers.Add(computers[i]._computers[j]);
}
}));
var threads = threadsAdd.ToList();
foreach (var thread in threads)
{
thread.Start();
}
**//4. wait for all threads to finish**
foreach (var thread in threads)
{
thread.Join();
}
**5.** WriteToFile();
Write("Program finished execution");
}
Редактировать:
Какспросил сузит это до: Как создать потокобезопасное добавление, удалить методы - запустить их в нескольких потоках, в то время как в классе Компьютеры, имеющего массив ограниченного размера - блокирование потоков, когда массив пуст или заполнен. Всего записей: 90, массив класса Компьютеры = [45];
Следует также сказать, что я специально обязан не использовать одновременные коллекции.
код, если необходимо !