/
Aufgabe2.c
291 lines (268 loc) · 12 KB
/
Aufgabe2.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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <stdlib.h>
#define MAX 16
#define MAXZEICHEN 30
#define ALPHASIZE 26
#define DEFAULT 0
#define CONTROLEXIT
const int p1terminated = 10;
const int p2terminated = 20;
const int cterminated = 30;
void *status; /* thread result */
int result[4];
int controllexit=0;
void* status;
char alphabet[ALPHASIZE] = "abcdefghijklmnopqrstuvwxyz";
char alphabet2[ALPHASIZE] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char *p_alpha = alphabet;
char *p_alpha2 = alphabet2;
int p1flag=1;
int p2flag=1;
int cflag=1;
int zaehler=0;
int i;
pthread_t threads[4];
#define p_alpha_start (char *)alphabet
#define p_alpha_end (char *)(alphabet + ALPHASIZE-1)
#define p_alpha_start2 (char *)alphabet2
#define p_alpha_end2 (char *)(alphabet2 + ALPHASIZE-1)
char zeichen;
pthread_mutex_t rb_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t rp1_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t rp2_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t rc_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t not_empty_condvar = PTHREAD_COND_INITIALIZER;
pthread_cond_t not_full_condvar = PTHREAD_COND_INITIALIZER;
pthread_cond_t p1_unlock = PTHREAD_COND_INITIALIZER;
pthread_cond_t p2_unlock = PTHREAD_COND_INITIALIZER;
pthread_cond_t c_unlock = PTHREAD_COND_INITIALIZER;
int thread_id[4] = {0,1,2,3};
typedef struct {
int buffer[MAX];
int *p_in;
int *p_out;
int count;
}rb;
rb x = { {0}, NULL, NULL, 0};
rb *p_rb = &x;
#define p_start (int *)(p_rb -> buffer)
#define p_end (int *)((p_rb -> buffer) + MAX-1)
void* p_1_w(void *pid);
void* p_2_w(void *pid);
void* consumer(void *pid);
void* control(void *pid);
int main(int argc, char* argv[])
{
//pthread_t threads[4];
printf("Start des Beispiels \n");
//printf("Argumente verfuegbar: ARGC\n", 3*argc);
p_rb -> p_in = p_start;
p_rb -> p_out = p_start;
p_rb -> count = 0;
printf("Counter value %d\n", p_rb ->count);
pthread_attr_t my_thread_attr; // Thread Attribut
struct sched_param my_prio;
pthread_attr_init(&my_thread_attr);
pthread_attr_setinheritsched(&my_thread_attr, PTHREAD_EXPLICIT_SCHED); // Freigabe der Parameteränd.
pthread_attr_setschedpolicy(&my_thread_attr, SCHED_FIFO);
my_prio.sched_priority = 10; // Priority ändern
pthread_attr_setschedparam(&my_thread_attr, &my_prio);
// Threads erstellen
pthread_create(&threads[2], NULL, control, (void *)&thread_id[2]);
pthread_create(&threads[0], NULL, p_1_w, (void *)thread_id);
pthread_create(&threads[1], NULL, p_2_w, (void *)&thread_id[1]);
pthread_create(&threads[3], NULL, consumer, (void *)&thread_id[3]);
// Controller join und status abfangen
pthread_join(threads[2], &status);
// Wenn erfolgreich beendet
if (status == 0) {
printf("Control join erfolgreich!\n");
pthread_cond_signal(&p1_unlock); // signal für das Freigeben, wenn p1 gestoppt ist.
pthread_cond_signal(&p2_unlock); // signal für das Freigeben, wenn p2 gestoppt ist.
pthread_cond_signal(&c_unlock); // signal für das Freigeben, wenn c gestoppt ist.
pthread_cancel(threads[0]); // beenden
pthread_cancel(threads[1]); // beenden
pthread_cancel(threads[3]); // beenden
}
//for(i = 0; i<4; i++) {
result[0] = pthread_join(threads[0], NULL); // &status
result[1] = pthread_join(threads[1], NULL); // &status
result[3] = pthread_join(threads[3], NULL); // &status
//printf("Exit status: %d\n", *(int *)status); // Speicherzugriffsfehler
//result[i] = *(int *)status;
//}
// vosichthalber vor dem Join ein Signal für den jeweiligen Thread mit condtion schicken.
printf("Ende nach Join der Threads\n");
//printf("Control Thread returns: %d\n",result[2]);
printf("Producer_1 Thread returns: %d\n",result[0]);
printf("Producer_2 Thread returns: %d\n",result[1]);
printf("Consumer Thread returns: %d\n",result[3]);
return 0;
}
void menu()
{
printf("***************Menu*************\n");
printf("TE 1: Start / Stopp Producer_1\n");
printf("TE 2: Start / Stopp Producer_2\n");
printf("TE c oder C: Start / Stop Consumer\n");
printf("TE q oder Q: Terminiert die Threads, sodass der Main_Thread das System beendet.\n");
printf("TE h: Menu\n");
}
// Wenn Flag gesetzt ist, heißt es, der Thread läuft, wenn nicht, ist er gestoppt
//läuft solange bis q oder Q gedrückt wird -> return 0
void *control(void *pid)
{
while (1) {
char eingabe;
//menu();
eingabe = getchar(); // blokiert hier
switch(eingabe) {
case '1':
pthread_mutex_lock(&rp1_mutex); // Ressourcen Reservieren
if (p1flag==1) // Falls flag gesetzt ist -> stoppen
p1flag=0;
else {// starten
p1flag=1;
pthread_cond_signal(&p1_unlock); // Signal für p1_unlock, da es gestartet werden soll
}
pthread_mutex_unlock(&rp1_mutex); // Ressourcen Freigeben
break;
case '2':
pthread_mutex_lock(&rp2_mutex); // Ressourcen Reservieren
if (p2flag==1) // Falls flag gesetzt ist -> stoppen
p2flag=0;
else {// starten
p2flag=1;
pthread_cond_signal(&p2_unlock); // Signal für p1_unlock, da es gestartet werden soll
}
pthread_mutex_unlock(&rp2_mutex); // Ressourcen Freigeben
break;
case 'c': case 'C':
pthread_mutex_lock(&rc_mutex); // Ressourcen Reservieren
if (cflag==1) // Falls flag gesetzt ist -> stoppen
cflag=0;
else {// starten
cflag=1;
pthread_cond_signal(&c_unlock); // Signal für p1_unlock, da es gestartet werden soll
}
pthread_mutex_unlock(&rc_mutex); // Ressourcen Freigeben
break;
case 'q': case 'Q':
return (void *)0;
break;
case 'h': case 'H': menu();
break;
default:
//printf("Kein Eingabe wurde festgestellt!");
//return (void *)1;
break;
}
}
}
void* p_1_w(void *pid)
{
while (1)
{
if (p1flag==0) { // Wenn flag nicht gesetzt ist, heißt der Thread soll stoppen -> wait for signal
printf("p1 waiting...\n");
pthread_mutex_lock(&rp1_mutex); // Reservierung der Ressourcen für den aktuellen Thread
pthread_cond_wait(&p1_unlock, &rp1_mutex); // warten auf Signal mit p1_unlock -> wieder starten von p1
pthread_mutex_unlock(&rp1_mutex); // Freigabe der Ressourcen
}
pthread_mutex_lock(&rb_mutex); // Reservierung der Ressourcen für den aktuellen Thread
while (p_rb-> count >= MAX) { // Wenn counter >= MAX -> Ringpuffer ist voll -> es kann nichts mehr geschrieben werden, bis platz frei ist -> wait for signal not_full
pthread_cond_wait(¬_full_condvar, &rb_mutex);
}
//Fall er aus der While-Schleife raus ist-> er hat ein signal zum Aufwachen bekommen, darf also weiter arbeiten
pthread_testcancel(); // sicheres Cancel
zeichen = (*p_alpha); // nächstes Zeichen holen
*p_rb ->p_in = zeichen; // Zeichen im nächsten verfübaren Platz im Puffer, schreiben
if (p_rb -> p_in == p_end) // Wenn das Ende erreicht ist -> vom Anfang an starten
p_rb -> p_in = p_start;
else
p_rb ->p_in++; // Zeigt auf das nächste verfügbaren Platz im Ringpuffer
printf("Geschrieben %c \n", zeichen);
p_rb -> count++; // Count um eins erhören
if (p_alpha == p_alpha_end) // Fall das Alphabet durch ist -> vorne wieder anfangen
p_alpha = p_alpha_start;
else
p_alpha++; // zeigt auf das nächste Zeichen im Alphabet
pthread_cond_signal(¬_empty_condvar); // Signal für consumer, das er starten werden kann, falls er gestoppt ist
pthread_mutex_unlock(&rb_mutex); // Freigabe der Ressourcen
sleep(3); // um ein anderen Thread ran zu lassen
}
return((void *) &p1terminated);
}
void* p_2_w(void *pid)
{
while (1)
{
if (p2flag==0) { // Wenn flag nicht gesetzt ist, heißt der Thread soll stoppen -> wait for signal
printf("p2 waiting...\n");
pthread_mutex_lock(&rp2_mutex); // Reservierung der Ressourcen für den aktuellen Thread
pthread_cond_wait(&p2_unlock, &rp2_mutex); // warten auf Signal mit p1_unlock -> wieder starten von p2
pthread_mutex_unlock(&rp2_mutex); // Freigabe der Ressourcen
}
pthread_mutex_lock(&rb_mutex); // Reservierung der Ressourcen für den aktuellen Thread
while (p_rb-> count >= MAX) { // Wenn counter >= MAX -> Ringpuffer ist voll -> es kann nichts mehr geschrieben werden, bis platz frei ist -> wait for signal not_full
pthread_cond_wait(¬_full_condvar, &rb_mutex);
}
//Fall er aus der While-Schleife raus ist-> er hat ein signal zum Aufwachen bekommen, darf also weiter arbeiten
pthread_testcancel(); // sicheres Cancel
zeichen = (*p_alpha2); // nächstes Zeichen holen
*p_rb ->p_in = zeichen; // Zeichen im nächsten verfübaren Platz im Puffer, schreiben
if (p_rb -> p_in == p_end) // Wenn das Ende erreicht ist -> vom Anfang an starten
p_rb -> p_in = p_start;
else
p_rb ->p_in++; // Zeigt auf das nächste verfügbaren Platz im Ringpuffer, was ein neues Zeichen darauf geschrieben kann
printf("Geschrieben %c \n", zeichen);
p_rb -> count++; // Count um eins erhören
if (p_alpha2 == p_alpha_end2) // Fall das Alphabet durch ist -> vorne wieder anfangen
p_alpha2 = p_alpha_start2;
else
p_alpha2++; // zeigt auf das nächste Zeichen im Alphabet
pthread_cond_signal(¬_empty_condvar); // Signal für consumer, das er starten werden kann, falls er gestoppt ist
pthread_mutex_unlock(&rb_mutex); // Freigabe der Ressourcen
sleep(3); // um ein anderen Thread ran zu lassen
}
return((void *) &p2terminated);
}
void* consumer(void *pid)
{
while (1){
if (cflag==0) { // Wenn flag nicht gesetzt ist, heißt der Thread soll stoppen -> wait for signal
printf("consumer waiting...\n");
pthread_mutex_lock(&rc_mutex); // Reservierung der Ressourcen für den aktuellen Thread
pthread_cond_wait(&c_unlock, &rc_mutex); // warten auf Signal mit p1_unlock -> wieder starten von consumer
pthread_mutex_unlock(&rc_mutex); // Freigabe der Ressourcen
}
pthread_mutex_lock(&rb_mutex); // Reservierung der Ressourcen für den aktuellen Thread
while (p_rb-> count <= 0) { //Solange count <=0 -> ist nichts mehr zum Lesen im Puffer -> wait for signal not_empty
pthread_cond_wait(¬_empty_condvar, &rb_mutex);
}
//Fall er aus der While-Schleife raus ist-> er hat ein signal zum Aufwachen bekommen, darf also weiter arbeiten
pthread_testcancel(); // sicheres Cancel
zeichen = *p_rb ->p_out; // nächstes Zeichen, das gelesen kann, holen
if (zaehler < MAXZEICHEN) { // Max erreicht
printf("Gelesen %c \n", zeichen);
zaehler++;
}
else {
printf("Gelesen %c \n", zeichen);
zaehler=0;
}
*p_rb ->p_out = DEFAULT; // löscht das Zeichen, was bereist gelesen wurde.
if (p_rb -> p_out == p_end) // Wenn das Ende erreicht ist -> vom Anfang an starten
p_rb -> p_out = p_start;
else
p_rb ->p_out++; // Zeigt auf das nächste Platz im Ringpuffer, was gelesen kann
p_rb -> count--;
pthread_cond_signal(¬_full_condvar); // Signal für consumer, das er starten werden kann, falls er gestoppt ist
pthread_mutex_unlock(&rb_mutex); // Freigabe der Ressourcen
sleep(2); // um ein anderen Thread ran zu lassen
}
return((void *) &cterminated);
}