«Синхронизация потоков»
Постановка задачи:
Один поток производит данные, другой поток их потребляет. В промежуток времени между
изготовлением и потреблением данные хранятся в буфере.
Пример использования: Конвейер команд в Unix.
Исходные данные:
Данные хранятся в циклическом буфере. Циклический буфер описывается некоторой
областью памяти, указателем начала данных и указателем конца данных. Поток-поставщик
записывает данные в конец буфера, поток-потребитель считывает их с начала буфера. После записи
или чтения соответствующим образом меняются указатели начала и конца.
Операции чтения/записи должны быть выполнены как взаимоисключающие.
Если операция чтения выполняется над пустым буфером (указатель начала = указатель
конца), поток-потребитель должен быть заблокирован на условной переменной до тех пор, пока
поток-поставщик не запишет в буфер какие-нибудь данные. Если операция записи выполняется над
полным буфером, поток-поставщик должен также быть заблокирован на условной переменной до тех
пор, пока поток-потребитель не считает из буфера какие-нибудь данные.
Размер буфера – не менее 10 символов.
Поток-поставщик и поток-потребитель работают в бесконечном цикле.
Поток-поставщик производит по одному символу в последовательности 0,1,2...9,0,1,... и
записывает его в буфер через случайный интервал времени 0,5 – 2 сек.
Поток-потребитель считывает по одному символу через случайный интервал времени 0,5 – 2
сек из буфера и выводит их на экран в виде сообщений (например, Символ 0, Символ 1,...)
Каждый поток совершая операцию с буфером выводит на экран информацию о текущем
состоянии буфера до и после операции, тип операции, символ, состояние условной переменной.
Задание 1.1
Лист
Лабораторная работа №3 ТОГУ, ИС-51, Храмцов А.А.
по Системному ПО 1
Сначала выполняется поток-потомок, затем поток-родитель.
Т.к. поток-потомок успевает выполниться быстрее без задержки.
2) функции потока-родителя
Задание 1.2
После исключения pthread_mutex_unlock(&my_sync) из порождённого потока программа
не может завершиться, т.к. порожденный поток не освободил мьютекс и участок кода в основном
потоке, заключенный в него, оказался недоступен.
Задание 1.3
После исключения pthread_cond_signal(&rx) программа не может завершиться, т.к.
основной поток остается заблокирован переменой состояния rx.
Лист
Лабораторная работа №3 ТОГУ, ИС-51, Храмцов А.А.
по Системному ПО 2
Задание 2
Листинг
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <iostream>
#include <fstream>
#include <string.h>
#include <cstdlib>
#include <math.h>
#include <sys/errno.h>
#include <queue>
queue<string> ThreadOutputToPrint;
bool IsPushing = false;
bool IsPopping = false;
pthread_mutex_t PushPop_Mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t IsPushingPopping_Condition = PTHREAD_COND_INITIALIZER;
float ProviderSleepInterval = 0;
float ConsumerSleepInterval = 0;
public:
CircularBuffer(int BufferLength)
{
Init(BufferLength);
};
void Init(int NewbufferLength)
{
if (Buffer != nullptr)
{
delete Buffer;
}
ElementCount = 0;
LastReadIndex = 0;
LastWriteIndex = 0;
Buffer = new BufferValueType[NewbufferLength];
Лист
Лабораторная работа №3 ТОГУ, ИС-51, Храмцов А.А.
по Системному ПО 3
Length = NewbufferLength;
};
void Read_ThreadSafe(BufferValueType& Element)
{
pthread_mutex_lock(&BufferIsBusy);
while (ElementCount == 0)
{
pthread_cond_wait(&IsFullCondition, &BufferIsBusy);
}
Element = Buffer[LastReadIndex];
ElementCount--;
LastReadIndex = (LastReadIndex + 1) % Length;
pthread_cond_signal(&IsFullCondition);
pthread_mutex_unlock(&BufferIsBusy);
};
Buffer[LastWriteIndex] = NewElement;
ElementCount++;
LastWriteIndex = (LastWriteIndex + 1) % Length;
pthread_cond_signal(&IsFullCondition);
pthread_mutex_unlock(&BufferIsBusy);
};
};
Лист
Лабораторная работа №3 ТОГУ, ИС-51, Храмцов А.А.
по Системному ПО 6