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

Contents of /trunk/livstidsfanger.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 9 - (show annotations) (download)
2014-11-07T12:40:00Z (10 years, 1 month ago) by trond
Content type: text/plain
File size: 6416 byte(s)
Gjorde koden litt mer portabel, siden srandomdev() stort sett bare
finnes i FreeBSD, mens andre OS har kanskje srandom() for å plante et
frø i tallgeneratoren.

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