Michael Mächtel 7 年之前
父節點
當前提交
62d6152cf1

+ 14
- 0
files/hw9.txt 查看文件

@@ -0,0 +1,14 @@
1
+./hw9/README.md
2
+./hw9/simu1/QUESTIONS.md
3
+./hw9/simu1/README.md
4
+./hw9/simu1/main-common.c
5
+./hw9/simu1/main-header.h
6
+./hw9/simu1/mythreads.h
7
+./hw9/simu1/vector-avoid-hold-and-wait.c
8
+./hw9/simu1/vector-deadlock.c
9
+./hw9/simu1/vector-global-order.c
10
+./hw9/simu1/vector-header.h
11
+./hw9/simu1/vector-nolock.c
12
+./hw9/simu1/vector-try-wait.c
13
+./hw9/task1/README.md
14
+./hw9/task2/README.md

+ 33
- 0
hw9/README.md 查看文件

@@ -0,0 +1,33 @@
1
+# hw9
2
+
3
+## Tasks
4
+
5
+To fulfill **hw9** you have to solve:
6
+
7
+- task1
8
+- task2
9
+- simu1
10
+
11
+## Files
12
+
13
+You find already or reuse some files for rust tasks. Please remember to
14
+use cargo to create a new project for each task and copy the given files
15
+into their dedicated directories.
16
+
17
+
18
+## Pull-Request
19
+
20
+Please merge any accepted reviews into your branch. If you are ready
21
+with the homework, all tests run, please create a pull request named
22
+
23
+**hw9**.
24
+
25
+## hw9 credits
26
+
27
+| Task     | max. Credits | Comment                 |
28
+|:---------|:-------------|:------------------------|
29
+| task1    | 1            |  |
30
+| simu1    | 1,5          |                         |
31
+| task2    | 1,5          |                         |
32
+| Deadline | +1           |                         |
33
+| =        | 5            |                         |

+ 24
- 0
hw9/simu1/Makefile 查看文件

@@ -0,0 +1,24 @@
1
+
2
+ALL = vector-deadlock vector-global-order vector-try-wait vector-avoid-hold-and-wait vector-nolock
3
+COMMON = vector-header.h main-common.c main-header.h
4
+
5
+all: $(ALL)
6
+
7
+clean:
8
+	rm -f $(ALL) *~
9
+
10
+vector-deadlock: vector-deadlock.c $(COMMON)
11
+	gcc -o vector-deadlock vector-deadlock.c -Wall -pthread -O
12
+
13
+vector-global-order: vector-global-order.c $(COMMON)
14
+	gcc -o vector-global-order vector-global-order.c -Wall -pthread -O
15
+
16
+vector-try-wait: vector-try-wait.c $(COMMON)
17
+	gcc -o vector-try-wait vector-try-wait.c -Wall -pthread -O
18
+
19
+vector-avoid-hold-and-wait: vector-avoid-hold-and-wait.c $(COMMON)
20
+	gcc -o vector-avoid-hold-and-wait vector-avoid-hold-and-wait.c -Wall -pthread -O
21
+
22
+vector-nolock: vector-nolock.c $(COMMON)
23
+	gcc -o vector-nolock vector-nolock.c -Wall -pthread -O
24
+

+ 74
- 0
hw9/simu1/QUESTIONS.md 查看文件

@@ -0,0 +1,74 @@
1
+# QUESTIONS Synchronisation: Real Bugs
2
+
3
+This homework lets you explore some real code that deadlocks (or avoids
4
+deadlock). The different versions of code correspond to different
5
+approaches to avoiding deadlock in a simplified vector add() routine.
6
+Specifically:
7
+
8
+- `vector-deadlock.c`: This version of vector add() does not try to
9
+  avoid deadlock and thus may indeed do so.
10
+- `vector-global-order.c`: This version acquires locks in a global order
11
+  to avoid deadlock.
12
+- `vector-try-wait.c`: This version is willing to release a lock when it
13
+  senses deadlock might occur.
14
+- `vector-avoid-hold-and-wait.c`: This version uses a global lock around
15
+  lock acquisition to avoid deadlock.
16
+- `vector-nolock.c`: This version uses an atomic fetch-and-add instead
17
+  of locks.
18
+
19
+See the README for details on these programs and their common substrate.
20
+
21
+## Questions
22
+
23
+1. First let’s make sure you understand how the programs generally work,
24
+   and some of the key options. Study the code in the file called
25
+   `vector-deadlock.c`, as well as in `main-common.c` and related files.
26
+
27
+   Now, run **./vector-deadlock -n 2 -l 1 -v**, which instantiates two
28
+   threads (`-n 2`), each of which does one vector add (`-l 1`), and
29
+   does so in verbose mode (`-v`). Make sure you understand the output.
30
+   How does the output change from run to run?
31
+
32
+2. Now add the `-d` flag, and change the number of loops (`-l`) from 1
33
+   to higher numbers. What happens? Does the code (always) deadlock?
34
+
35
+3. How does changing the number of threads (`-n`) change the outcome of
36
+   the program? Are there any values of `-n` that ensure no deadlock
37
+   occurs?
38
+
39
+4. Now examine the code in `vector-global-order.c`. First, make sure you
40
+   understand what the code is trying to do; do you understand why the
41
+   code avoids deadlock? Also, why is there a special case in this
42
+   vector *add()* routine when the source and destination vectors are
43
+   the same?
44
+
45
+5. Now run the code with the following flags: `-t -n 2 -l 100000 -d`.
46
+   How long does the code take to complete? How does the total time
47
+   change when you increase the number of loops, or the number of
48
+   threads?
49
+
50
+6. What happens if you turn on the parallelism flag (`-p`)? How much
51
+   would you expect performance to change when each thread is working on
52
+   adding different vectors (which is what `-p` enables) versus working
53
+   on the same ones?
54
+
55
+7. Now let’s study `vector-try-wait.c`. First make sure you understand
56
+   the code. Is the first call to pthread mutex `trylock()` really
57
+   needed?
58
+
59
+   Now run the code. How fast does it run compared to the global order
60
+   approach? How does the number of retries, as counted by the code,
61
+   change as the number of threads increases?
62
+
63
+8. Now let’s look at `vector-avoid-hold-and-wait.c`. What is the main
64
+   problem with this approach? How does its performance compare to the
65
+   other versions, when running both with `-p` and without it?
66
+
67
+9. Finally, let’s look at `vector-nolock.c`. This version doesn’t use
68
+   locks at all; does it provide the exact same semantics as the other
69
+   versions? Why or why not?
70
+
71
+10. Now compare its performance to the other versions, both when threads
72
+    are working on the same two vectors (no `-p`) and when each thread
73
+    is working on separate vectors (`-p`). How does this no-lock version
74
+    perform?

+ 82
- 0
hw9/simu1/README.md 查看文件

@@ -0,0 +1,82 @@
1
+# README Synchronisation: Real Bugs
2
+
3
+This homework lets you play around with a number of ways to implement a
4
+small, deadlock-free vector object in C. The vector object is quite
5
+limited (e.g., it only has *add()* and *init()* functions) but is just
6
+used to illustrate different approaches to avoiding deadlock.
7
+
8
+Some files that you should pay attention to are as follows. They, in
9
+particular, are used by all the variants in this homework.
10
+
11
+- `mythreads.h` The usual wrappers around many different pthread (and
12
+  other) library calls, so as to ensure they are not failing silently
13
+
14
+- `vector-header.h` A simple header for the vector routines, mostly
15
+  defining a fixed vector size and then a struct that is used per vector
16
+  (vector_t)
17
+
18
+- `main-header.h` A number of global variables common to each different
19
+  program
20
+
21
+- `main-common.c` Contains the *main()* routine (with arg parsing) that
22
+  initializes two vectors, starts some threads to access them (via a
23
+  *worker()* routine), and then waits for the many *vector_add()*'s to
24
+  complete
25
+
26
+The variants of this homework are found in the following files. Each
27
+takes a different approach to dealing with concurrency inside a "vector
28
+addition" routine called *vector_add()*; examine the code in these files
29
+to get a sense of what is going on. They all use the files above to make
30
+a complete runnable program.
31
+
32
+- `vector-deadlock.c` This version blithely grabs the locks in a
33
+  particular order (dst then src). By doing so, it creates an
34
+  "invitation to deadlock", as one thread might call *vector_add(v1,
35
+  v2)* while another concurrently calls *vector_add(v2, v1)*.
36
+
37
+- `vector-global-order.c` This version of *vector_add()* grabs the locks
38
+  in a total order, based on address of the vector.
39
+
40
+- `vector-try-wait.c` This version of *vector_add()* uses
41
+  *pthread_mutex_trylock()* to attempt to grab locks; when the try
42
+  fails, the code releases any locks it may hold and goes back to the
43
+  top and tries it all over again.
44
+
45
+- `vector-avoid-hold-and-wait.c` This version of *vector_add()* ensures
46
+  it can't get stuck in a hold and wait pattern by using a single lock
47
+  around lock acquisition.
48
+
49
+- `vector-nolock.c` This version of *vector_add()* doesn't even use
50
+  locks; rather, it uses an atomic fetch-and-add to implement the
51
+  *vector_add()* routine. Its semantics (as a result) are slightly
52
+  different.
53
+
54
+Type "make" (and read the Makefile) to build each of five executables.
55
+
56
+    prompt> make
57
+
58
+Then you can run a program by simply typing its name:
59
+
60
+    prompt> ./vector-deadlock
61
+
62
+Each program takes the same set of arguments (see `main-common.c` for
63
+details):
64
+
65
+`-d` This flag turns on the ability for threads to deadlock. When you
66
+pass -d to the program, every other thread calls *vector_add()* with the
67
+vectors in a different order, e.g., with two threads, and -d enabled,
68
+Thread 0 calls *vector_add(v1, v2)* and Thread 1 calls *vector_add(v2,
69
+v1)*
70
+
71
+`-p` This flag gives each thread a different set of vectors to call
72
+*add()* upon, instead of just two vectors. Use this to see how things
73
+perform when there isn't contention for the same set of vectors.
74
+
75
+`-n num_threads` Creates some number of threads; you need more than one
76
+to deadlock.
77
+
78
+`-l loops` How many times should each thread call *vector_add()*?
79
+
80
+`-v` Verbose flag: prints out a little more about what is going on.
81
+
82
+`-t` Turns on timing and shows how long everything took.

+ 139
- 0
hw9/simu1/main-common.c 查看文件

@@ -0,0 +1,139 @@
1
+
2
+vector_t v[2 * MAX_THREADS];
3
+
4
+// used to ensure print outs make sense
5
+pthread_mutex_t print_lock = PTHREAD_MUTEX_INITIALIZER;
6
+
7
+void usage(char *prog) {
8
+    fprintf(stderr, "usage: %s [-d (turn on deadlocking behavior)] [-l loops] [-n num_threads] [-t (do timing)] [-v (for verbose)]\n", prog);
9
+    exit(1);
10
+}
11
+
12
+// only called by one thread (not thread-safe)
13
+void vector_init(vector_t *v, int value) {
14
+    int i;
15
+    for (i = 0; i < VECTOR_SIZE; i++) {
16
+	v->values[i] = value;
17
+    }
18
+    Pthread_mutex_init(&v->lock, NULL); 
19
+}
20
+
21
+// only called by one thread (not thread-safe)
22
+void vector_print(vector_t *v, char *str) {
23
+    int i;
24
+    for (i = 0; i < VECTOR_SIZE; i++) {
25
+	printf("%s[%d] %d\n", str, i, v->values[i]);
26
+    }
27
+}
28
+
29
+void print_info(int call_return, int thread_id, int v0, int v1) {
30
+    if (verbose == 0)
31
+	return;
32
+    Pthread_mutex_lock(&print_lock);
33
+    int j;
34
+    for (j = 0; j < thread_id; j++) printf("              ");
35
+    if (call_return) 
36
+	printf("<-add(%d, %d)\n", v0, v1);
37
+    else
38
+	printf("->add(%d, %d)\n", v0, v1);
39
+    Pthread_mutex_unlock(&print_lock);
40
+}
41
+
42
+typedef struct __thread_arg_t {
43
+    int tid;
44
+    int vector_add_order;
45
+    int vector_0;
46
+    int vector_1;
47
+} thread_arg_t;
48
+
49
+void *worker(void *arg) {
50
+    thread_arg_t *args = (thread_arg_t *) arg;
51
+    int i, v0, v1;
52
+    for (i = 0; i < loops; i++) {
53
+	if (args->vector_add_order == 0) { 
54
+	    v0 = args->vector_0;
55
+	    v1 = args->vector_1;
56
+	} else {
57
+	    v0 = args->vector_1;
58
+	    v1 = args->vector_0;
59
+	}
60
+
61
+	print_info(0, args->tid, v0, v1);
62
+
63
+	vector_add(&v[v0], &v[v1]);
64
+
65
+	print_info(1, args->tid, v0, v1);
66
+    }
67
+    return NULL;
68
+}
69
+
70
+int main(int argc, char *argv[]) {
71
+    opterr = 0;
72
+    int c;
73
+    while ((c = getopt (argc, argv, "l:n:vtdp")) != -1) {
74
+	switch (c) {
75
+	case 'l':
76
+	    loops = atoi(optarg);
77
+	    break;
78
+	case 'n':
79
+	    num_threads = atoi(optarg);
80
+	    break;
81
+	case 'v':
82
+	    verbose = 1;
83
+	    break;
84
+	case 't':
85
+	    do_timing = 1;
86
+	    break;
87
+	case 'd':
88
+	    cause_deadlock = 1;
89
+	    break;
90
+	case 'p':
91
+	    enable_parallelism = 1;
92
+	    break;
93
+	default:
94
+	    usage(argv[0]);
95
+	}
96
+    }
97
+
98
+    assert(num_threads < MAX_THREADS);
99
+
100
+    pthread_t pid[MAX_THREADS];
101
+    thread_arg_t args[MAX_THREADS];
102
+    int i;
103
+    for (i = 0; i < num_threads; i++) {
104
+	args[i].tid = i;
105
+	if (enable_parallelism == 0) {
106
+	    args[i].vector_0 = 0;
107
+	    args[i].vector_1 = 1;
108
+	} else {
109
+	    args[i].vector_0 = i * 2;
110
+	    args[i].vector_1 = i * 2 + 1;
111
+	}
112
+
113
+	if (cause_deadlock && i % 2 == 1)
114
+	    args[i].vector_add_order = 1;
115
+	else
116
+	    args[i].vector_add_order = 0;
117
+    }
118
+
119
+    for (i = 0; i < 2 * MAX_THREADS; i++) 
120
+	vector_init(&v[i], i);
121
+
122
+    double t1 = Time_GetSeconds();
123
+
124
+    for (i = 0; i < num_threads; i++) 
125
+	Pthread_create(&pid[i], NULL, worker, (void *) &args[i]);
126
+    for (i = 0; i < num_threads; i++) 
127
+	Pthread_join(pid[i], NULL); 
128
+
129
+    double t2 = Time_GetSeconds();
130
+
131
+    fini();
132
+    if (do_timing) {
133
+	printf("Time: %.2f seconds\n", t2 - t1);
134
+    }
135
+
136
+    //vector_print(&v[0], "v1");
137
+    //vector_print(&v[1], "v2");
138
+    return 0;
139
+}

+ 13
- 0
hw9/simu1/main-header.h 查看文件

@@ -0,0 +1,13 @@
1
+#ifndef __main_header_h__
2
+#define __main_header_h__
3
+
4
+#define MAX_THREADS (100)
5
+
6
+int loops = 1;
7
+int verbose = 0;
8
+int num_threads = 2;
9
+int do_timing = 0;
10
+int cause_deadlock = 0;
11
+int enable_parallelism = 0;
12
+
13
+#endif // __main_header_h__

+ 52
- 0
hw9/simu1/mythreads.h 查看文件

@@ -0,0 +1,52 @@
1
+#ifndef __MYTHREADS_h__
2
+#define __MYTHREADS_h__
3
+
4
+#include <pthread.h>
5
+#include <assert.h>
6
+#include <stdlib.h>
7
+#include <sys/time.h>
8
+
9
+void *Malloc(size_t size) {
10
+    void *rc = malloc(size);
11
+    assert(rc != NULL);
12
+    return rc;
13
+}
14
+
15
+double Time_GetSeconds() {
16
+    struct timeval t;
17
+    int rc = gettimeofday(&t, NULL);
18
+    assert(rc == 0);
19
+    return (double) ((double)t.tv_sec + (double)t.tv_usec / 1e6);
20
+}
21
+
22
+void Pthread_mutex_init(pthread_mutex_t *mutex,
23
+			const pthread_mutexattr_t *attr) {
24
+    int rc = pthread_mutex_init(mutex, attr);
25
+    assert(rc == 0);
26
+}
27
+
28
+
29
+void Pthread_mutex_lock(pthread_mutex_t *m) {
30
+    int rc = pthread_mutex_lock(m);
31
+    assert(rc == 0);
32
+}
33
+                                                                                
34
+void Pthread_mutex_unlock(pthread_mutex_t *m) {
35
+    int rc = pthread_mutex_unlock(m);
36
+    assert(rc == 0);
37
+}
38
+                                                                                
39
+void Pthread_create(pthread_t *thread, const pthread_attr_t *attr, 	 
40
+		    void *(*start_routine)(void*), void *arg) {
41
+    int rc = pthread_create(thread, attr, start_routine, arg);
42
+    assert(rc == 0);
43
+}
44
+
45
+void Pthread_join(pthread_t thread, void **value_ptr) {
46
+    int rc = pthread_join(thread, value_ptr);
47
+    assert(rc == 0);
48
+}
49
+
50
+
51
+
52
+#endif // __MYTHREADS_h__

+ 32
- 0
hw9/simu1/vector-avoid-hold-and-wait.c 查看文件

@@ -0,0 +1,32 @@
1
+#include <stdio.h>
2
+#include <stdlib.h>
3
+#include <string.h>
4
+
5
+#include <unistd.h>
6
+
7
+#include "mythreads.h"
8
+
9
+#include "main-header.h"
10
+#include "vector-header.h"
11
+
12
+// use this to make lock acquisition ATOMIC
13
+pthread_mutex_t global = PTHREAD_MUTEX_INITIALIZER; 
14
+
15
+void vector_add(vector_t *v_dst, vector_t *v_src) {
16
+    // put GLOBAL lock around all lock acquisition...
17
+    Pthread_mutex_lock(&global);
18
+    Pthread_mutex_lock(&v_dst->lock);
19
+    Pthread_mutex_lock(&v_src->lock);
20
+    Pthread_mutex_unlock(&global);
21
+    int i;
22
+    for (i = 0; i < VECTOR_SIZE; i++) {
23
+	v_dst->values[i] = v_dst->values[i] + v_src->values[i];
24
+    }
25
+    Pthread_mutex_unlock(&v_dst->lock);
26
+    Pthread_mutex_unlock(&v_src->lock);
27
+}
28
+
29
+void fini() {}
30
+
31
+#include "main-common.c"
32
+

+ 24
- 0
hw9/simu1/vector-deadlock.c 查看文件

@@ -0,0 +1,24 @@
1
+#include <stdio.h>
2
+#include <stdlib.h>
3
+#include <string.h>
4
+#include <unistd.h>
5
+
6
+#include "mythreads.h"
7
+
8
+#include "main-header.h"
9
+#include "vector-header.h"
10
+
11
+void vector_add(vector_t *v_dst, vector_t *v_src) {
12
+    Pthread_mutex_lock(&v_dst->lock);
13
+    Pthread_mutex_lock(&v_src->lock);
14
+    int i;
15
+    for (i = 0; i < VECTOR_SIZE; i++) {
16
+	v_dst->values[i] = v_dst->values[i] + v_src->values[i];
17
+    }
18
+    Pthread_mutex_unlock(&v_dst->lock);
19
+    Pthread_mutex_unlock(&v_src->lock);
20
+}
21
+
22
+void fini() {}
23
+
24
+#include "main-common.c"

+ 35
- 0
hw9/simu1/vector-global-order.c 查看文件

@@ -0,0 +1,35 @@
1
+#include <stdio.h>
2
+#include <stdlib.h>
3
+#include <string.h>
4
+#include <unistd.h>
5
+
6
+#include "mythreads.h"
7
+
8
+#include "main-header.h"
9
+#include "vector-header.h"
10
+
11
+void vector_add(vector_t *v_dst, vector_t *v_src) {
12
+    if (v_dst < v_src) {
13
+	Pthread_mutex_lock(&v_dst->lock);
14
+	Pthread_mutex_lock(&v_src->lock);
15
+    } else if (v_dst > v_src) {
16
+	Pthread_mutex_lock(&v_src->lock);
17
+	Pthread_mutex_lock(&v_dst->lock);
18
+    } else {
19
+	// special case: src and dst are the same
20
+	Pthread_mutex_lock(&v_src->lock);
21
+    }
22
+    int i;
23
+    for (i = 0; i < VECTOR_SIZE; i++) {
24
+	v_dst->values[i] = v_dst->values[i] + v_src->values[i];
25
+    }
26
+    Pthread_mutex_unlock(&v_src->lock);
27
+    if (v_dst != v_src) 
28
+	Pthread_mutex_unlock(&v_dst->lock);
29
+}
30
+
31
+void fini() {}
32
+
33
+
34
+#include "main-common.c"
35
+

+ 13
- 0
hw9/simu1/vector-header.h 查看文件

@@ -0,0 +1,13 @@
1
+#ifndef __vector_header_h__
2
+#define __vector_header_h__
3
+
4
+#define VECTOR_SIZE (100)
5
+
6
+typedef struct __vector {
7
+    pthread_mutex_t lock;
8
+    int values[VECTOR_SIZE];
9
+} vector_t;
10
+
11
+
12
+#endif // __vector_header_h__
13
+

+ 31
- 0
hw9/simu1/vector-nolock.c 查看文件

@@ -0,0 +1,31 @@
1
+#include <stdio.h>
2
+#include <stdlib.h>
3
+#include <string.h>
4
+#include <unistd.h>
5
+
6
+#include "mythreads.h"
7
+
8
+#include "main-header.h"
9
+#include "vector-header.h"
10
+
11
+// taken from https://en.wikipedia.org/wiki/Fetch-and-add
12
+int fetch_and_add(int * variable, int value) {
13
+    asm volatile("lock; xaddl %%eax, %2;"
14
+		 :"=a" (value)                  
15
+		 :"a" (value), "m" (*variable)  
16
+		 :"memory");
17
+    return value;
18
+}
19
+
20
+void vector_add(vector_t *v_dst, vector_t *v_src) {
21
+    int i;
22
+    for (i = 0; i < VECTOR_SIZE; i++) {
23
+	fetch_and_add(&v_dst->values[i], v_src->values[i]);
24
+    }
25
+}
26
+
27
+void fini() {}
28
+
29
+
30
+#include "main-common.c"
31
+

+ 36
- 0
hw9/simu1/vector-try-wait.c 查看文件

@@ -0,0 +1,36 @@
1
+#include <stdio.h>
2
+#include <stdlib.h>
3
+#include <string.h>
4
+#include <unistd.h>
5
+
6
+#include "mythreads.h"
7
+
8
+#include "main-header.h"
9
+#include "vector-header.h"
10
+
11
+int retry = 0;
12
+
13
+void vector_add(vector_t *v_dst, vector_t *v_src) {
14
+  top:
15
+    if (pthread_mutex_trylock(&v_dst->lock) != 0) {
16
+	goto top;
17
+    }
18
+    if (pthread_mutex_trylock(&v_src->lock) != 0) {
19
+	retry++;
20
+	Pthread_mutex_unlock(&v_dst->lock);
21
+	goto top;
22
+    }
23
+    int i;
24
+    for (i = 0; i < VECTOR_SIZE; i++) {
25
+	v_dst->values[i] = v_dst->values[i] + v_src->values[i];
26
+    }
27
+    Pthread_mutex_unlock(&v_dst->lock);
28
+    Pthread_mutex_unlock(&v_src->lock);
29
+}
30
+
31
+void fini() {
32
+    printf("Retries: %d\n", retry);
33
+}
34
+
35
+#include "main-common.c"
36
+

+ 106
- 0
hw9/task1/README.md 查看文件

@@ -0,0 +1,106 @@
1
+# Homework hw9 task1
2
+
3
+[TOC]: #
4
+
5
+# Table of Contents
6
+- [1.1. Ziel](#11-ziel)
7
+- [1.2. Protokollbeschreibung](#12-protokollbeschreibung)
8
+    - [1.2.1 STAGE](#121-stage)
9
+    - [1.2.2 RETRIEVE](#122-retrieve)
10
+- [2.1 Aufgabe](#21-aufgabe)
11
+    - [2.2.1 Crate](#221-crate)
12
+    - [2.2.2 Testabdeckung](#222-testabdeckung)
13
+    - [2.2.3 Fehlerbehandlung und Rückgabetyp](#223-fehlerbehandlung-und-rückgabetyp)
14
+- [3.1 Hilfen](#31-hilfen)
15
+
16
+
17
+## 1.1. Ziel
18
+
19
+Ziel dieser Aufgabe ist es, einen Parser für ein simples Protokoll zu
20
+implementieren, das in den folgenden Aufgaben verwendet wird.
21
+
22
+Das Protokoll beschreibt das Bereitstellen und Abrufen von Daten von
23
+einem Server.
24
+
25
+## 1.2. Protokollbeschreibung
26
+
27
+Das Protokoll kennt 2 Kommandos: Bereitstellen und Abrufen. Weitere
28
+Kommandos sind zunächst nicht zugelassen. Das Protokoll arbeitet
29
+zeilenweise, d.h. ein newline ('\\n') beendet das Kommando.
30
+
31
+Die Kommandos folgen diesem Format:
32
+
33
+    <KOMMANDO> [DATEN]\n
34
+
35
+Werden keine Daten erwartet, folgt das newline-Zeichen direkt auf das
36
+Kommando. Das Kommando muss immer in Großbuchstaben geschrieben werden.
37
+
38
+Der Zeilenumbruch ist _nicht_ optional.
39
+
40
+### 1.2.1 STAGE
41
+
42
+Das STAGE-Kommando überträgt eine Nachricht an den Server. Die Daten
43
+dürfen selbst keine newline enthalten. Es ist erlaubt, eine _leere_
44
+Nachricht zu veröffentlichen.
45
+
46
+Beispiele:
47
+
48
+    STAGE Hallo, hier ist eine kleine Nachricht!\n
49
+    STAGE \n
50
+
51
+### 1.2.2 RETRIEVE
52
+
53
+Das RETRIEVE-Kommando entnimmt eine Nachricht. Es erhält keine Daten.
54
+
55
+Beispiel:
56
+
57
+    RETRIEVE\n
58
+
59
+## 2.1 Aufgabe
60
+
61
+Implementieren Sie einen Parser für dieses Protokoll. Der Parser sollte so
62
+simpel wie möglich gehalten sein.
63
+
64
+Es ist insbesondere erlaubt, die Eingabe als einzelne Zeile zu erwarten.
65
+Die Trennung der Eingabe in einzelne Zeilen ist dem aufrufenden Code
66
+überlassen.
67
+
68
+Enthält der Input mehrere newlines, darf der Rest ohne Fehler verworfen
69
+weden.
70
+
71
+Folgendes öffentliche Interface ist vorgegeben:
72
+
73
+```rust
74
+pub fn parse(message: &str) -> ... {
75
+   //...
76
+}
77
+```
78
+
79
+### 2.2.1 Crate
80
+
81
+Implementieren Sie den Parser als eigene Crate, die Sie dann in den
82
+weiteren Aufgaben einbinden können, statt den Code zu kopieren. Sie
83
+können diese Crate später entweder auf Github veröffentlichen oder über
84
+Pfade einbinden.
85
+
86
+### 2.2.2 Testabdeckung
87
+
88
+Achten Sie auf eine ausreichende Testabdeckung, um möglichst alle
89
+illegalen Fälle abzudecken. Achten Sie vor allem darauf, dass keine
90
+Daten verloren gehen!
91
+
92
+### 2.2.3 Fehlerbehandlung und Rückgabetyp
93
+
94
+Finden Sie einen geeigneten Rückgabetyp, der das gefundene Kommando, als
95
+auch eventuelle Fehler kommuniziert. Kombinieren Sie dies mit einer
96
+geeigneten Darstellung des Kommandos.
97
+
98
+Allokieren Sie die gefunden Daten als `String`.
99
+
100
+## 3.1 Hilfen
101
+
102
+Die Dokumentation von [`str`][str] enthält viele wichtige Hinweise.
103
+
104
+
105
+[str]: https://doc.rust-lang.org/std/primitive.str.html
106
+

Loading…
取消
儲存