/
task.c
156 lines (149 loc) · 5.33 KB
/
task.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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <string.h>
struct queue{
int *v;
int head;
int tail;
int size;
int maxsize;
};
struct queue *queue_create(int maxsize)
{
struct queue *q = malloc(sizeof(*q));
if (q != NULL){
q->v = malloc(sizeof(int)*(maxsize + 1));
if (q->v == NULL){
free(q); return NULL;
}
q->maxsize = maxsize;
q->size = 0;
q->head = maxsize + 1;
q->tail = 0;
}
return q;
}
void queue_free(struct queue *q){
free(q->v);
free(q);
}
int queue_size(struct queue *q)
{
return q->size;
}
int queue_enqueue(struct queue *q, int value){
if (q->head == q->tail + 1)
return -1;
q->v[q->tail++] = value;
q->tail = q->tail % (q->maxsize + 1);
q->size++;
return 0;
}
int queue_dequeue(struct queue *q){
if (q->head % (q->maxsize + 1) == q->tail){
return -1;
}
q->head = q->head % (q->maxsize + 1);
q->size--;
return q->v[q->head++];
}
static void *producer(void* arg);
static void *consumer(void* arg);
struct queue *queueSource;//буфер для хранения промежуточных результатов
pthread_mutex_t* myMutex;//мьютекс для синхронизации доступа к очереди
pthread_cond_t* onPutCondition; //событие,которое будет активироваться при добавлении производителем в очередь данных
pthread_cond_t* onTakeCondition; //событие, которое активируется при взятии элемента из очереди потребителем
FILE *f;//исходный файл с чилами
int totalSum; //сумма всех чисел в файле
int main(){
f = fopen("source.txt", "r");
if (f == NULL)
exit(EXIT_FAILURE);
queueSource = queue_create(100);
//инициализация mutex и события
myMutex = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
onPutCondition = (pthread_cond_t*)malloc(sizeof(pthread_cond_t));
pthread_cond_init(onPutCondition, NULL);
pthread_cond_init(onTakeCondition, NULL);
pthread_mutex_init(myMutex, NULL);
pthread_t prod, cons;//производитель, потребитель
//инициализация потока производителя
int resCreate = pthread_create(&prod, NULL, producer, NULL);
if(resCreate != 0){
printf("Error creating producer-thread\n");
exit(1);
}
resCreate = pthread_join(prod, NULL);
if(resCreate != 0)
{
printf("Thread producer joining failed\n");
exit(1);
}
//инициализация потока потребителя
resCreate = pthread_create(&cons, NULL, consumer, NULL);
if(resCreate != 0){
printf("Error creating consumer-thread\n");
exit(1);
}
resCreate = pthread_join(cons, NULL);
if(resCreate != 0)
{
printf("Thread consumer joining failed\n");
exit(1);
}
fclose(f);
//printf("TotalSum in file: %d\n", totalSum);
return 0;
}
/*
*функция производителя: читает файл строка за строкой
*в каждой строке выделяет числа, суммирует их
*и кладет результат в общий буфер - queueSource
*/
static void *producer(void* arg)
{ pthread_mutex_lock(myMutex);
//если очередь переполнена, то производитель ждет, чтобы потребитель снял оттуда элемент
while(queue_size(queueSource) > 100)
pthread_cond_wait(onTakeCondition, myMutex);
//парсит строку
char *line = NULL; int temp;
size_t len = 0;
ssize_t read;
while ((read = getline(&line, &len, f)) != -1) {
char *token;
char *rest = line;
int sumIntoStr = 0;
token = strtok(rest, " ");
while(token != NULL){
temp = atoi(token);
sumIntoStr += temp;
token = strtok(NULL, " ");
}
printf("in producer: %d\n", sumIntoStr);
//кладём сумму строки в очередь
queue_enqueue(queueSource, sumIntoStr);
if (queue_size(queueSource) - 1 <= 0) //очередь была пустая, а теперь нет - об этом нужно оповестить потребителя
pthread_cond_signal(onPutCondition);
}
pthread_mutex_unlock(myMutex);
}
/*
*функция потребителя: берет число из очереди, пока она не пустая
*и суммирует в общую переменную totalSum
*/
static void *consumer(void* arg)
{
pthread_mutex_lock(myMutex);
//если очередь пуста, то ждем, пока туда производитель не положет
while(queue_size(queueSource) <= 0)
pthread_cond_wait(onPutCondition, myMutex);
totalSum += queue_dequeue(queueSource);
printf("in consumer: %d\n",totalSum);
//потребитель уведомлет производителя об уменьшении элементов в очереди, на случай, если она была переполнена
pthread_cond_signal(onTakeCondition);
pthread_mutex_unlock(myMutex);
}