МИНОБРНАУКИ РОССИИ САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ ЭЛЕКТРОТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ «ЛЭТИ» ИМ. В.И. УЛЬЯНОВА (ЛЕНИНА) Кафедра ВТ ОТЧЕТ по лабораторной работе № 10 по дисциплине «Организация процессов и программирования Linux» Тема: Синхронизация процессов с помощью семафоров Студентка гр. 7308 Латышева В.А. Преподаватель Разумовский Г.В. Санкт-Петербург 2020 Цель работы Знакомство с организацией семафоров, системными функциями, обеспечивающими управление семафорами, и их использованием для решения задач взаимоисключения и синхронизации. Первая работа Текст программы provider.cpp #include <iostream> #include <sys/sem.h> #include <sys/shm.h> #include <fstream> #define BUFFER_SIZE 10 class cycleBuffer { private: char buffer[BUFFER_SIZE] = {'\0'}; int size = 0; public: bool empty() { return size == 0; } void push(char symbol) { ++size; for (int i = size; i > 0; --i) { buffer[i] = buffer[i - 1]; } buffer[0] = symbol; } char pop() { char symbol = buffer[size]; buffer[size] = '\0'; if (size!= 0) size--; return symbol; } }; void clear(cycleBuffer *cycleBuffer, int semID, int bufID) { shmdt(cycleBuffer); shmctl(bufID, IPC_RMID, 0); semctl(semID, IPC_RMID, 0); exit(-1); } int main() { int bufKey = 2036, semKey = 2037; int bufID = shmget(bufKey, sizeof(cycleBuffer), 0666 | IPC_CREAT); if (bufID == -1){ std::cout << "Wasn't able to create buffer\n"; exit(-1); } cycleBuffer *cycleBuf = (cycleBuffer *)shmat(bufID, 0, 0); int semID = semget(semKey, 4, 0666 | IPC_CREAT); if (semID == -1){ std::cout << "Wasn't able to create semaphore\n"; exit(-1); } if (semctl(semID, 0, SETVAL, BUFFER_SIZE) == -1) { // buffer size for provider std::cout << "The first semaphore wasn't initialized\n"; clear(cycleBuf, semID, bufID); } if (semctl(semID, 1, SETVAL, 1) == -1) { // provider end work std::cout << "The second semaphore wasn't initialized\n"; clear(cycleBuf, semID, bufID); } if (semctl(semID, 2, SETVAL, 1) == -1) { // customer end work std::cout << "The third semaphore wasn't initialized\n"; clear(cycleBuf, semID, bufID); } if (semctl(semID, 3, SETVAL, 0) == -1) { // block access for buffer std::cout << "The fourth semaphore wasn't initialized\n"; clear(cycleBuf, semID, bufID); } struct sembuf checkBuffer, accessBuffer[2], freeBuffer[2], endWork[2]; checkBuffer.sem_num = 0; // check if buffer is full checkBuffer.sem_op = 0; checkBuffer.sem_flg = IPC_NOWAIT; accessBuffer[0].sem_num = 3; // check if buffer is busy accessBuffer[0].sem_op = 0; accessBuffer[1].sem_num = 3; // access buffer accessBuffer[1].sem_op = 1; freeBuffer[0].sem_num = 3; // free buffer freeBuffer[0].sem_op = -1; freeBuffer[1].sem_num = 0; // symbol was added to buffer freeBuffer[1].sem_op = -1; endWork[0].sem_num = 1; // provider is over endWork[0].sem_op = -1; endWork[1].sem_num = 2; // check if customer is over endWork[1].sem_op = 0; std::ifstream file("file.txt"); if(!file.is_open()){ std::cout << "Wasn't able to open the file\n"; clear(cycleBuf, semID, bufID); } char ch; while(!file.eof()) { if(semop(semID, &checkBuffer, 1) != -1) // check if buffer is full continue; semop(semID, accessBuffer, 2); ch = file.get(); cycleBuf->push((char)ch); semop(semID, freeBuffer, 2); } semop(semID, &endWork[0], 1); // provider is over semop(semID, &endWork[1], 1); // check if customer is over clear(cycleBuf, semID, bufID); return 0; } customer.cpp #include <iostream> #include <sys/sem.h> #include <sys/shm.h> #define BUFFER_SIZE 10 class cycleBuffer { private: char buffer[BUFFER_SIZE] = {'\0'}; int size = 0; public: bool empty() { return size == 0; } void push(char symbol) { ++size; for (int i = size; i > 0; --i) { buffer[i] = buffer[i - 1]; } buffer[0] = symbol; } char pop() { char symbol = buffer[size]; buffer[size] = '\0'; if (size!= 0) size--; return symbol; } }; int main() { int bufKey = 2036, semKey = 2037; int bufID = shmget(bufKey, sizeof(cycleBuffer), 0666 | IPC_CREAT | IPC_EXCL); if (bufID != -1) { std::cout << "Wasn't able to connect to buffer\n"; exit(-1); } else bufID = shmget(bufKey, sizeof(cycleBuffer), 0666 | IPC_CREAT); cycleBuffer *cycleBuf = (cycleBuffer *)shmat(bufID, 0, 0); int semID = semget(semKey, 4, 0666 | IPC_CREAT | IPC_EXCL); if (semID != -1) { std::cout << "Wasn't able to connect to semaphore\n"; exit(-1); } else semID = semget(semKey, 4, 0666 | IPC_CREAT); struct sembuf accessBuffer[2], freeBuffer[2], endWork[2]; accessBuffer[0].sem_num = 3; // check if buffer is busy accessBuffer[0].sem_op = 0; accessBuffer[1].sem_num = 3; // access buffer accessBuffer[1].sem_op = 1; freeBuffer[0].sem_num = 3; // free buffer freeBuffer[0].sem_op = -1; freeBuffer[1].sem_num = 0; // symbol was removed from buffer freeBuffer[1].sem_op = 1; endWork[0].sem_num = 2; // customer is over endWork[0].sem_op = -1; endWork[1].sem_num = 1; // check if provider is over endWork[1].sem_op = 0; endWork[1].sem_flg = IPC_NOWAIT; std::cout << "File content: \n"; while(semop(semID, &endWork[1], 1) == -1 || !cycleBuf->empty()) { int x = semctl(semID, 0, GETVAL, 0); if (semctl(semID, 0, GETVAL, 0) == BUFFER_SIZE) continue; semop(semID, accessBuffer, 2); std::cout << cycleBuf->pop(); semop(semID, freeBuffer, 2); } std::cout << std::endl; semop(semID, &endWork[0], 1); // customer is over shmdt(cycleBuf); return 0; } Результат работы программы Вторая работа Reader.cpp #include <iostream> #include <fstream> #include <sys/sem.h> #include <unistd.h> int main (int argc, char **argv) { int period = atoi(argv[1]); int semID = semget(854, 3, IPC_CREAT | IPC_EXCL | 0666); if (semID != -1) { semctl(semID, 0, SETVAL, 1); semctl(semID, 1, SETVAL, 0); semctl(semID, 2, SETVAL, 0); } else semID = semget(854, 3, IPC_CREAT | 0666); std::ifstream file("output.txt"); if (!file.is_open()) { std::cout << "Error: file wasn't opened\n"; exit(-1); } struct sembuf addReader[1], removeReader[1], waitWriters[1]; addReader[0].sem_num = 2; addReader[0].sem_op = 1; removeReader[0].sem_num = 2; removeReader[0].sem_op = -1; waitWriters[0].sem_num = 1; waitWriters[0].sem_op = 0; semop(semID, waitWriters, 1); semop(semID, addReader, 1); std::string line; while (!file.eof()) { getline(file, line); std::cout << line << std::endl; sleep(period); } semop(semID, removeReader, 1); file.close(); return 0; } Writer.cpp #include <iostream> #include <fstream> #include <sys/sem.h> #include <unistd.h> int main (int argc, char **argv) { int writerNumber = atoi(argv[1]); int N = atoi(argv[2]); int period = atoi(argv[3]); int semID = semget(854, 3, IPC_CREAT | IPC_EXCL | 0666); bool creator = false; if (semID != -1) { semctl(semID, 0, SETVAL, 1); semctl(semID, 1, SETVAL, 0); semctl(semID, 2, SETVAL, 0); creator = true; } else semID = semget(854, 3, IPC_CREAT | 0666); std::ofstream file("output.txt", std::ios::app); if (!file.is_open()) { std::cout << "Error: file wasn't opened\n"; exit(-1); } struct sembuf busyFile[1], freeFile[1], addWriter[1], removeWriter[1], waitReaders[1]; busyFile[0].sem_num = 0; busyFile[0].sem_op = -1; freeFile[0].sem_num = 0; freeFile[0].sem_op = 1; addWriter[0].sem_num = 1; addWriter[0].sem_op = 1; removeWriter[0].sem_num = 1; removeWriter[0].sem_op = -1; waitReaders[0].sem_num = 2; waitReaders[0].sem_op = 0; for (int i = 0; i < N; ++i) { semop(semID, addWriter, 1); semop(semID, waitReaders, 1); semop(semID, busyFile, 1); file << "Writer " << writerNumber << std::endl; std::cout << "Writer " << writerNumber << std::endl; semop(semID, removeWriter, 1); semop(semID, freeFile, 1); sleep(period); } while (true) if (semop(semID, waitReaders, 1) == 0) break; if (creator) semctl(semID, IPC_RMID, 0); file.close(); return 0; } Результаты работы