/[livstidsfanger]/trunk/livstidsfanger.c
ViewVC logotype

Contents of /trunk/livstidsfanger.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (show annotations) (download)
2014-11-19T19:32:53Z (10 years ago) by trond
Content type: text/plain
File size: 6920 byte(s)
Det er greit å frigjøre CPU-en etter én runde i fangetråden.

1 // Programmet bruker ISO C 2011 (ISO/IEC 9899:2011) og Pthreads (IEEE Std 1003.1c-2001). -*- coding: utf-8 -*-
2 // Løsning programmert av Trond Endrestøl <Trond.Endrestol@ximalas.info>, 2014-11-06.
3
4 // $Ximalas$
5
6 #if __STDC_VERSION__ < 199901L
7 #error det er tvilsomt om du får kompilert denne kildekoden med så gammel C-kompilator
8 #endif
9
10 #include <errno.h>
11 #include <pthread.h>
12 #include <sched.h>
13 #include <signal.h>
14 #include <stdbool.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <time.h>
19 #include <unistd.h>
20
21 #if _POSIX_THREADS < 200112L
22 #error her mangler det støtte for POSIX Threads anno 2001
23 #endif
24
25 #if __STDC_VERSION__ >= 201112L
26 #include <stdnoreturn.h>
27 #else
28 #define noreturn
29 #endif
30
31 #define ANTALL_LIVSTIDSFANGER 19U
32
33 static unsigned antallBesok[ANTALL_LIVSTIDSFANGER];
34
35 static size_t tellendeLivstidsfange;
36 static unsigned antallLivstidsfanger;
37
38 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
39 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
40 static bool brytere[2U];
41
42 noreturn void *livstidsfange(void *arg);
43 void visResultater(void);
44 void signalhandler(int sig);
45
46 noreturn int main(int argc, char **argv)
47 {
48 size_t i;
49 pthread_t tid = pthread_self();
50
51 if (argc >= 0) { // Bare for å få clang til å ti stille.
52 atexit(visResultater);
53 signal(SIGINT, signalhandler);
54 } // if
55
56 #ifdef __FreeBSD__
57 srandomdev();
58 #else
59 srandom((unsigned int)time(NULL));
60 #endif
61
62 memset((void *)&antallBesok, 0, sizeof(antallBesok));
63 brytere[0] = random() & 1;
64 brytere[1] = random() & 1;
65
66 tellendeLivstidsfange = random() % ANTALL_LIVSTIDSFANGER;
67
68 printf("bryter %u er i utgangspunktet vippet %s\n", 1U, brytere[0] == true ? "opp" : "ned");
69 printf("bryter %u er i utgangspunktet vippet %s\n", 2U, brytere[1] == true ? "opp" : "ned");
70 printf("livstidsfange %zu er utpekt som den tellende livstidsfange\n\n", tellendeLivstidsfange + 1);
71
72 puts("maintråden venter på å få låst mutex");
73 pthread_mutex_lock(&mutex);
74 puts("mutex er låst av maintråden");
75
76 for (i = 0; i < ANTALL_LIVSTIDSFANGER; i++) {
77 printf("maintråden oppretter livstidsfange %2zu\n", i + 1);
78
79 if ( (errno = pthread_create(&tid, NULL, livstidsfange, (void *)i)) != 0) {
80 fflush(stdout);
81 fprintf(stderr,
82 "%s: pthread_create(&tid, NULL, livstidsfange, (void *)%2zu) = %s (%d)\n",
83 argv[0], i, strerror(errno), errno);
84 fflush(stderr);
85 _exit(1);
86 } // if
87 } // for
88
89 // maintråden påtar seg rolla som fengselsdirektøren.
90 while (1) {
91 puts("fengselsdirektøren låser opp mutex");
92 pthread_mutex_unlock(&mutex);
93 puts("mutex er låst opp av fengselsdirektøren");
94
95 puts("fengselsdirektøren signalerer livstidsfangene");
96 pthread_cond_signal(&cond);
97 puts("signal er sendt fra fengselsdirektøren");
98
99 puts("fengselsdirektøren venter på å få låst mutex");
100 pthread_mutex_lock(&mutex);
101 puts("mutex er låst av fengselsdirektøren");
102 } // while
103 } // main()
104
105 noreturn void *livstidsfange(void *arg)
106 {
107 size_t i = (size_t)arg;
108
109 bool harVippetBryter1 = false;
110 bool bryter1HarVartOppe = false;
111
112 bool forrigeGangErGyldig = false;
113 bool forrigeGang = false;
114
115 // Den tellende livstidsfangen kan allerede nå telle seg selv.
116 if (i == tellendeLivstidsfange) {
117 antallLivstidsfanger++;
118 } // if
119
120 while (1) {
121 // Vente på tur.
122 printf("livstidsfange %2zu venter på å få låst mutex\n", i + 1);
123 pthread_mutex_lock(&mutex);
124 printf("livstidsfange %2zu har låst mutex\n", i + 1);
125
126 printf("livstidsfange %2zu venter på signal fra fengselsdirektøren\n", i + 1);
127 pthread_cond_wait(&cond, &mutex);
128 printf("livstidsfange %2zu har fått signal fra fengselsdirektøren og har låst mutex\n", i + 1);
129
130 // Utføre selve simuleringen ved å sjekke brytere, m.m.
131 antallBesok[i]++;
132 printf("livstidsfange %2zu har besøkt rommet %u gang%s\n", i + 1, antallBesok[i], antallBesok[i] == 1 ? "" : "er");
133
134 if (i == tellendeLivstidsfange) {
135 if (brytere[0] == false) {
136 printf("livstidsfange %2zu ser at bryter 1 er nede og vipper opp bryter 1\n", i + 1);
137 brytere[0] = true;
138 } // if
139 else {
140 brytere[0] = !brytere[0];
141 printf("livstidsfange %2zu vipper %s bryter 1\n", i + 1, brytere[0] == true ? "opp" : "ned");
142
143 if (forrigeGangErGyldig == true && forrigeGang == false) {
144 antallLivstidsfanger++;
145 printf("livstidsfange %2zu har talt opp %u livstidsfanger\n", i + 1, antallLivstidsfanger);
146
147 if (antallLivstidsfanger == ANTALL_LIVSTIDSFANGER) {
148 printf("livstidsfange %2zu avslutter simuleringen\n", i + 1);
149 exit(0);
150 } // if
151 } // if
152
153 forrigeGangErGyldig = true;
154 forrigeGang = brytere[0];
155 } // else
156 } // if
157 else { // Vanlig livstidsfange.
158 if (brytere[0] == true) {
159 printf("livstidsfange %2zu ser at bryter 1 er oppe, mens bryter 2 er %s\n", i + 1, brytere[1] == true ? "oppe" : "nede");
160 bryter1HarVartOppe = true;
161
162 brytere[1] = !brytere[1];
163 printf("livstidsfange %2zu vipper %s bryter 2\n", i + 1, brytere[1] == true ? "opp" : "ned");
164 } // if
165 else {
166 printf("livstidsfange %2zu ser at bryter 1 er nede, mens bryter 2 er %s\n", i + 1, brytere[1] == true ? "oppe" : "nede");
167
168 if (harVippetBryter1 == false && bryter1HarVartOppe == true) {
169 brytere[0] = !brytere[0];
170 printf("livstidsfange %2zu vipper %s bryter 1\n", i + 1, brytere[0] == true ? "opp" : "ned");
171
172 harVippetBryter1 = true;
173 } // if
174 else {
175 brytere[1] = !brytere[1];
176 printf("livstidsfange %2zu vipper %s bryter 2\n", i + 1, brytere[1] == true ? "opp" : "ned");
177 } // else
178 } // else
179 } // else
180
181 // Tusle ut av rommet.
182 printf("livstidsfange %2zu låser opp mutex\n", i + 1);
183 pthread_mutex_unlock(&mutex);
184 printf("livstidsfange %2zu har låst opp mutex\n", i + 1);
185
186 #ifdef _POSIX_PRIORITY_SCHEDULING
187 sched_yield();
188 #endif
189 } // while
190 } // livstidsfange()
191
192 void visResultater(void)
193 {
194 size_t i;
195
196 fflush(stderr);
197 fflush(stdout);
198
199 puts("\nResultater:\n");
200
201 printf("bryter %u er ved avslutning vippet %s\n", 1U, brytere[0] == true ? "opp" : "ned");
202 printf("bryter %u er ved avslutning vippet %s\n", 2U, brytere[1] == true ? "opp" : "ned");
203 printf("livstidsfange %2zu var den tellende livstidsfangen\n\n", tellendeLivstidsfange + 1);
204
205 for (i = 0; i < ANTALL_LIVSTIDSFANGER; i++) {
206 printf("livstidsfange %2zu: antall besøk: %u\n", i + 1, antallBesok[i]);
207 } // for
208 puts("");
209
210 printf("antall livstidsfanger talt av den tellende livstidsfangen er %u\n", antallLivstidsfanger);
211
212 fflush(stdout);
213 fflush(stdout);
214 } // visResultater()
215
216 void signalhandler(int sig)
217 {
218 if (sig == SIGINT) {
219 exit(1);
220 } // if
221 } // signalhandler()
222
223 // livstidsfanger.c

Properties

Name Value
svn:eol-style native
svn:keywords Ximalas=%H
svn:mime-type text/plain

svn@ximalas.info
ViewVC Help
Powered by ViewVC 1.3.0-dev