From b80183b9a32a940f71d3662956de7a28f6a77c8f Mon Sep 17 00:00:00 2001 From: M-Aksi Date: Mon, 26 May 2025 00:11:21 +0300 Subject: [PATCH] First commit. Finished project --- MyList.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++ MyList.h | 49 ++++++++++++++++++++ MyThreads.c | 106 +++++++++++++++++++++++++++++++++++++++++++ MyThreads.h | 22 +++++++++ delay.c | 16 +++++++ delay.h | 7 +++ main.c | 49 ++++++++++++++++++++ makefile | 26 +++++++++++ 8 files changed, 402 insertions(+) create mode 100644 MyList.c create mode 100644 MyList.h create mode 100644 MyThreads.c create mode 100644 MyThreads.h create mode 100644 delay.c create mode 100644 delay.h create mode 100644 main.c create mode 100644 makefile diff --git a/MyList.c b/MyList.c new file mode 100644 index 0000000..1d9daaa --- /dev/null +++ b/MyList.c @@ -0,0 +1,127 @@ +#include +#include +#include + +#include "MyList.h" +#define SIZE 10 // максимальный размер двоичного числа + + +// Функция для инициализации списка +void initList(DoublyLinkedList* list) { + list->head = NULL; + list->tail = NULL; + list->size = 0; +} + + +// Функция выделения памяти под новый узел +Node* createNode(int value) { + Node* newNode = (Node*)malloc(sizeof(Node)); + if (newNode == NULL) { + printf("Memory allocation error!\n"); + exit(1); // аварийное завершение + } + newNode->data = value; + newNode->prev = NULL; + newNode->next = NULL; + return newNode; +} + +// Функция добавления элемента в конец списка +void append(DoublyLinkedList* list, int value) { + Node* newElement = createNode(value); + if (list -> head == NULL){ // если список пустой + newElement -> prev = NULL; + list -> head = newElement; + } + else { // уже не пустой + newElement -> prev = list -> tail; // связь текущего с предыдущим + list -> tail -> next = newElement; // связь предыдущего с текущим + } + list -> tail = newElement; // переопределение конца(указателя) на новый элемент + ++(list -> size); // увеличение списка +} + +// Функция освобождения памяти +void freeList(DoublyLinkedList* list) { + Node* current = list->head; + while (current != NULL) { + Node* temp = current; + current = current->next; // освобождаем память, запоминая указатель на следующий элемент + free(temp); + } + list->head = NULL; // уничтожаем указатели непосредственно списка + list->tail = NULL; + list->size = 0; +} + +// Функция вывода списка от начала к концу +void printForward(const DoublyLinkedList* list){ + Node* current = list -> head; + printf("Dec list: "); + while(current != NULL){ + printf("%d ", current -> data); + current = current -> next; + } + printf("\n"); +} + +// Функция вывода списка от конца к началу +void printBackward(const DoublyLinkedList* list){ + Node* current = list -> tail; + printf("Dec list: "); + while(current != NULL){ + printf("%d ", current -> data); + current = current -> prev; + } + printf("\n"); +} + +void generateRandomList(DoublyLinkedList* list, int count){ + // Инициализация генератора случайных чисел + srand(time(NULL)); + for (int i = 0; i < count; ++i){ + append(list, rand() % 100); + } +} + +// Функция для вывода списка в двоичном виде +void printBinaryValue(const DoublyLinkedList* list) { + printf("Binary list: "); + Node* current = list -> head; + int numberDec; + int count = -1; + while(current != NULL){ + numberDec = current -> data; + int* numberBin = (int*)calloc(SIZE, sizeof(int)); + if (numberBin == NULL){ + printf("Memory allocation error!\n"); + exit(1); + } + //printf("%d ", numberDex); + numberBin[++count] = numberDec % 2; + while (numberDec != 0){ + numberDec /= 2; + numberBin[++count] = numberDec % 2; // добываем 0 и 1 из числа + } + + + // разворачиваем двоичное число + for (int i = 0; i < count / 2; ++i){ + int bubble = numberBin[i]; + numberBin[i] = numberBin[count - 1 - i]; // обмен крайних элементов, двигаемся к середине + numberBin[count - 1 - i] = bubble; + } + // вывод в консоль + for (int i = 0;i < count; ++i){ + printf("%d",numberBin[i]); + } + printf(" "); // пробел между двоичными числами + free(numberBin); // освобождаем память + numberBin = NULL; + numberDec = 0; + count = -1; + current = current -> next; + } + printf("\n"); +} \ No newline at end of file diff --git a/MyList.h b/MyList.h new file mode 100644 index 0000000..713e459 --- /dev/null +++ b/MyList.h @@ -0,0 +1,49 @@ +#ifndef MYLIST_H +#define MYLIST_H + +/* Концепция двухсвязного спиcка + +NULL <- [prev0 data0 next0] <-> [prev1 data1 next1] <-> [prev2 data2 next2] -> NULL + + Node0(head) Node1 Node2(tail) + + +next0 = &Node1 +next1 = &Node2 +next2 = NULL + +prev0 = NULL +prev1 = &Node0 +prev2 = &Node1 + +*/ + +// Cтруктура узла двухсвязного списка (один элемент списка) +typedef struct Node { + int data; + struct Node* prev; // указатель на прерыдущий элемент + struct Node* next; // указатель на следующий элемент +} Node; + +// Структура самого списка +typedef struct { + Node* head; // указатель на первый элемент + Node* tail; // указатель на последний элемент + int size; // счетчик элементов списка +} DoublyLinkedList; + + +void initList(DoublyLinkedList* list); +Node* createNode(int value); +void append(DoublyLinkedList* list, int value); +void freeList(DoublyLinkedList* list); + +void printForward(const DoublyLinkedList* list); +void printBackward(const DoublyLinkedList* list); + +void generateRandomList(DoublyLinkedList* list, int count); + +void printBinaryValue(const DoublyLinkedList* list); + + +#endif // MYLIST_H \ No newline at end of file diff --git a/MyThreads.c b/MyThreads.c new file mode 100644 index 0000000..5d12dff --- /dev/null +++ b/MyThreads.c @@ -0,0 +1,106 @@ +#include +#include +#include "MyThreads.h" + +// Функция для посчета нулевых битов в числе +int countZeroBits(int numberDec){ + int count = 0; + while(numberDec != 0){ + if (numberDec % 2 == 0){ + ++count; + } + numberDec /= 2; + } + return count; +} + +// Функция для подсчета единичных битов в числе +int countOneBits(int numberDec){ + int count = 0; + while(numberDec != 0){ + if (numberDec % 2 == 1){ + ++count; + } + numberDec /= 2; + } + return count; +} +// Функция инициализации и запуска потоков +void threadStart(ThreadArgs* args1, ThreadArgs* args2){ + // Создание потоков + pthread_t thread1; + pthread_t thread2; + + if (pthread_create(&thread1, NULL, threadExecution, args1) != 0) { + printf("Failed to create thread 1"); + exit(1); // аварийное завершение + } + if (pthread_create(&thread2, NULL, threadExecution, args2) != 0) { + printf("Failed to create thread 2"); + exit(1); // аварийное завершение + } + /* разбор функции pthread_create + &thread1 - Указатель на переменную типа pthread_t, в которую будет записан идентификатор созданного потока + NULL - Указатель на атрибуты потока (используем атрибуты по умолчанию) + threadExecution - Функция обработки данных в потоке + &args1 - Указатель на аргументы, которые будут переданы в функцию threadExecution + */ + + // Ожидание завершения потоков + pthread_join(thread1, NULL); + pthread_join(thread2, NULL); +} + +// функция выполнения обработки данных в потоке +void* threadExecution(void* args) { + ThreadArgs* targs = (ThreadArgs*)args; // преобразуем принятые аргументы в структуру + + Node* currentNode = NULL; // объявляем текущий узел + Node* nextNode = NULL; // и следующий + + currentNode = targs -> flag ? targs -> head : targs -> tail; + + while (1) { + + // блокируем список на время чтения узла + pthread_mutex_lock(targs -> listMutex); + + // разблокировка, если конец списка + if (currentNode == NULL) { + pthread_mutex_unlock(targs -> listMutex); + break; + } + + // Сохраняем данные и следующий узел локально + int data = currentNode -> data; + nextNode = targs -> flag ? currentNode -> next : currentNode -> prev; + + // теперь разблокируем список (чтение завершено) + pthread_mutex_unlock(targs -> listMutex); + + // Обработка данных + if (targs -> flag) { + targs -> countZero += countZeroBits(data); + } else { + targs -> countOne += countOneBits(data); + } + ++(targs -> countNodes); + currentNode = nextNode; + } + targs = NULL; + return NULL; +} + +// функция для вывода результата в консоль +void threadPrint(ThreadArgs* args1, ThreadArgs* args2){ + printf("\n"); + printf("Thread 1:\n"); + printf("Zero bits: %d\n", args1 -> countZero); + printf("Count nodes: %d\n", args1 -> countNodes); + printf("\n"); + printf("Thread 2:\n"); + printf("One bits: %d\n", args2 -> countOne); + printf("Count nodes: %d\n", args2 -> countNodes); +} + + diff --git a/MyThreads.h b/MyThreads.h new file mode 100644 index 0000000..d1532e9 --- /dev/null +++ b/MyThreads.h @@ -0,0 +1,22 @@ +#ifndef MYTHREADS_H +#define MYTHREADS_H +#include "MyList.h" + +// Структура аргументов для работы с потоком +typedef struct { + Node* head; // Указатель на голову списка + Node* tail; // Указатель на хвост списка + int countZero; // Счетчик нулевых битов (для потока 1) + int countOne; // Счетчик единичных битов (для потока 2) + int countNodes; // Счетчик обработанных элементов + int flag; // Флаг направления обхода (1 - от головы, 0 - от хвоста) + pthread_mutex_t* listMutex; // Мьютекс для синхронизации доступа к списку +} ThreadArgs; + +int countZeroBits(int numberDec); +int countOneBits(int numberDec); +void threadStart(ThreadArgs* args1, ThreadArgs* args2); +void* threadExecution(void* args); +void threadPrint(ThreadArgs* args1, ThreadArgs* args2); + +#endif //MYTHREADS_H \ No newline at end of file diff --git a/delay.c b/delay.c new file mode 100644 index 0000000..0c5df59 --- /dev/null +++ b/delay.c @@ -0,0 +1,16 @@ +#include "delay.h" + +#ifdef _WIN32 +#include +#else +#include +#endif + +// функция для задержки консоли в Linux или Windows +void delay_ms(int milliseconds) { + #ifdef _WIN32 + Sleep(milliseconds); + #else + usleep(milliseconds * 1000); + #endif +} \ No newline at end of file diff --git a/delay.h b/delay.h new file mode 100644 index 0000000..9e0c050 --- /dev/null +++ b/delay.h @@ -0,0 +1,7 @@ +#ifndef DELAY_H +#define DELAY_H + + +void delay_ms(int milliseconds); + +#endif // DELAY_H \ No newline at end of file diff --git a/main.c b/main.c new file mode 100644 index 0000000..4af3a56 --- /dev/null +++ b/main.c @@ -0,0 +1,49 @@ +#include +#include +#include "MyList.h" +#include "delay.h" +#include "MyThreads.h" + + +int main() { + // Подготовка данных + int sizeList = 0; + printf("Enter a number of type int: "); + scanf("%d", &sizeList); + printf("\n"); + DoublyLinkedList MyList; + initList(&MyList); + generateRandomList(&MyList, sizeList); + + // Смотрим на подготовленные данные + printForward(&MyList); // десятичный вид + printBinaryValue(&MyList); // двоичный вид + + // Многопоточность + + // Инициализация мьютекса + pthread_mutex_t listMutex = PTHREAD_MUTEX_INITIALIZER; + /* + Мьютексы нужны для защиты от одновременного + доступа сразу нескольких потоков к одному + обЪекту. Их необходимо использовать, если + предполагается, что список будет не просто + считываться, а изменяться в разных потоках. + + */ + + // Подготовка аргументов для потоков (инициализация структур) + ThreadArgs args1 = {MyList.head, MyList.tail, 0, 0, 0, 1, &listMutex}; // Поток 1 (от головы) + ThreadArgs args2 = {MyList.head, MyList.tail, 0, 0, 0, 0, &listMutex}; // Поток 2 (от хвоста) + + // Запуск многопоточной обработки + threadStart(&args1, &args2); + + // Вывод результатов + threadPrint(&args1, &args2); + + delay_ms(5000); // задержка отображения в консоли (Linux|Windows) + pthread_mutex_destroy(&listMutex); // Уничтожение мьютекса + freeList(&MyList); // освобождение памяти + return 0; +} \ No newline at end of file diff --git a/makefile b/makefile new file mode 100644 index 0000000..048f2f1 --- /dev/null +++ b/makefile @@ -0,0 +1,26 @@ +CC = gcc # Используем компилятор gcc +CFLAGS = -Wall -Wextra # Флаги компиляции: включить все предупреждения +LDFLAGS = -lpthread # Флаги линковки: подключить pthread +TARGET = bdz_3 # Имя итогового исполняемого файла + +all: $(TARGET) # Сборка главной цели (TARGET) + +$(TARGET): main.o MyList.o delay.o MyThreads.o # Линковка object-файлов $^ — все зависимости, $@ — цель + $(CC) $^ -o $@ $(LDFLAGS) + +main.o: main.c MyList.h #$< — первая зависимость + $(CC) $(CFLAGS) -c $< -o $@ + +MyList.o: MyList.c MyList.h + $(CC) $(CFLAGS) -c $< -o $@ + +delay.o: delay.c delay.h + $(CC) $(CFLAGS) -c $< -o $@ + +MyThreads.o: MyThreads.c MyThreads.h + $(CC) $(CFLAGS) -c $< -o $@ + +clean: # Удаление всех .o-файлов и бинарника + rm -f *.o $(TARGET) + +.PHONY: all clean \ No newline at end of file