finish week 1.5
This commit is contained in:
parent
462a45364a
commit
a31096e720
@ -60,3 +60,108 @@ When the frikandellen are all produced and consumed, there is finaly time for th
|
||||
> Adjust the consumer code as discussed above. Build the program and debug it with priorities 3, 2, and 1. Explain why the program stalls. Use the FreeRTOS aware Views to help you understand what is going on.
|
||||
|
||||
When the consumer wait for the first producer product it is holding on the `semPrintf` semaphore. This semaphore is also used at the beginning of the producers. Because the consumer has the highest priority it start first, takes `semPrintf` and wait for the producers. when the producers start they are going to wait for `semPrintf`, but it is only given free if the procures continue. Now all task are waiting for each other.
|
||||
|
||||
> D) Compile the (original) program and run it with the priorities: Consumer = 1, frikandel Producer = 2 and kroket producer = 3. Explain the output. Be precise in your explanation. Explain why the kroketten are consumed first. Explain why there are 9 kroketten still consumed after the kroketten producer has stopped. Also explain why there are nine frikandellen still consumed after the frikandel producer has stopped. Only eight of them fit in the buffer! Is the behaviour of the semaphore correct in a real-time environment? Why (not)?
|
||||
|
||||
```
|
||||
Enter priority for process Consumer [1..15]: 1
|
||||
Enter priority for process Frikandel Producer [1..15]: 2
|
||||
Enter priority for process Kroket Producer [1..15]: 3
|
||||
Output for Consumer priority = 1 frikandel Producer priority = 2 Kroket Producer priority = 3
|
||||
Thread: 0x200020a0 with argument: K starts
|
||||
Thread: 0x20001b20 with argument: F starts
|
||||
Thread: 0x200015a0 starts
|
||||
KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK\
|
||||
> KKKKKKKKKKKKThread: 0x200020a0 stops
|
||||
KKKKKKKKKFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\
|
||||
> FFFFFFFFFFFFFFFFFFFFFThread: 0x20001b20 stops
|
||||
FFFFFFFFFThread: 0x200015a0 stops
|
||||
```
|
||||
|
||||
The kroket producer has the highest priority in this case, so it will start until the buffer if full. Then the frikandel producer will initialise but produce nothing, because it is already full. Then the consumer will start and consume one kroket, then it will be overtaken by the kroket producer. This back and forward will continue until there are no kroketten left. Now the same back and forward will continue, but with the frikandel producer instead of the kroket producer. The first 9 of the products consumed are will kroketten. 8 of them were still in the buffer and one stored in a local variable in the consumer. This is because the consumer halts at the moment the semaphore `semEmpty` is posted (increased) and this happens in between getting it from the buffer and printing it. When all the frikandellen are all produced the same thing happens. There are also 9 frikandellen consumed after it's producer finished.
|
||||
|
||||
> E) Try to predict (without debugging the program) what the flow of execution will be when the priorities are changed to: Consumer = 1, Frikandel Producer = 3 and Kroket producer = 2. Test your prediction by running the program.
|
||||
|
||||
This is the same as D, but the priorities of the frikandel producer and kroket producer are swapped. So the result will also be the same where F and K are swapped.
|
||||
|
||||
> F) Try to predict (without debugging the program) what the flow of execution will be when the priorities are changed to: Consumer = 2, Frikandel Producer = 1 and Kroket producer = 1. Test your prediction by running the program.
|
||||
|
||||
The producers will run with round-robin, so one after the other. The consumer has a higher priority than the producers, so all will end at the same time.
|
||||
|
||||
> G) Now finally, try to predict (without debugging the program) what the flow of execution will be when the priorities are changed to: Consumer = 1, Frikandel Producer = 2 and Kroket producer = 2. Think carefully! Test your prediction by running the program.
|
||||
|
||||
The producers are again will execute in round-robin, but because the consumer has a lower priority and is not waiting for data in the buffer, the first producer will fill the buffer. After the buffer is filled it will continue the same as F.
|
||||
|
||||
## Assignment 5.2
|
||||
|
||||
> In this assignment you are going to replace the buffer with a message queue.
|
||||
>
|
||||
> A) Copy the project buffer to buffer_mqueue in the Project Explorer of STM32- CubeIDE. Remove the Debug folder from the buffer_mqueue project, rename buffer.cfg to buffer_mqueue.cfg, and rename buffer.launch to buffer_- mqueue.launch. Open buffer_mqueue.launch and replace all occurrences of buffer with buffer_mqueue. Build and debug the project buffer_mqueueue to verify that it is a correct copy of project buffer.
|
||||
>
|
||||
>B) Replace the global variable buffer and the semaphores semMutualExclusive, semEmpty and semFilled with a message queue.
|
||||
|
||||
I stharted to remove all the old semaphores, the definition, creation and deletion in `main_thread()` and the contents of `get()` and `put(char c)`. Then looked at the examples library and saw `#include <mqueue.h>` with look like is necessary. Created a global variable to store the queue `mqd_t mqFood;`. I coppied the initialisation of the queue from the example and chanchd the name and size. and added it to `main_thread()` just after the semaphores are initialised.
|
||||
|
||||
```c
|
||||
struct mq_attr mqAttrs;
|
||||
mqAttrs.mq_maxmsg = SIZE;
|
||||
mqAttrs.mq_msgsize = sizeof(char);
|
||||
mqAttrs.mq_flags = 0;
|
||||
check_errno((int)( mqFood = mq_open("food", O_RDWR | O_CREAT, 0666, &mqAttrs) ));
|
||||
```
|
||||
|
||||
And the corresponding closing code at the end of `main_thread()`
|
||||
|
||||
```c
|
||||
check( mq_close(mqFood) );
|
||||
check( mq_unlink("food") );
|
||||
```
|
||||
|
||||
Then changed the `get()` and `put(char c)` function to the following.
|
||||
|
||||
```c
|
||||
void put(char c)
|
||||
{
|
||||
check_errno( mq_send(mqFood, (char *)&c, sizeof(c), 0) );
|
||||
}
|
||||
|
||||
char get(void)
|
||||
{
|
||||
char c = 0;
|
||||
check_errno( mq_receive(mqFood, (char *)&c, sizeof(c), NULL) );
|
||||
return c;
|
||||
}
|
||||
```
|
||||
|
||||
The first test I did the code could not find the definition of `O_RDWR` and `O_CREAT` used for `mq_open`. looking a second time at the includes of the example, I saw `#include <fcntl.h>` as missing from my code, so I added and it fixed the issue and it builds.
|
||||
|
||||
The first run it failed with the `check_errno` function at the `mq_open` after reading the source of `mq_open` the first place it can fail is because of an invalid name (the first argument). I looked back to the example code and saw it has a slash in front of the name, by adding this (both in `mq_open` and `mq_unlink`) it fixed the issue and was working.
|
||||
|
||||
The final full code is available at [/report-2/week_1.5/assignment_5.2/main.c](https://git.gay/LailaTheElf/RTS10_reports/src/branch/main/report-2/week_1.5/assignment_5.2/main.c)
|
||||
|
||||
## Assaginment 5.3
|
||||
|
||||
> In this assignment you are going to replace the semaphore with a mutex.
|
||||
>
|
||||
> A) Copy the project buffer_mqueue to buffer_mutex in the same way as described in assignment 5.2 part A.
|
||||
>
|
||||
> B) Replace the semaphore semPrintf with a mutex.
|
||||
|
||||
I replaced the definition of the semaphore with `pthread_mutex_t mutPrintf;`, the initialisation of the semaphore with the following
|
||||
|
||||
```c
|
||||
pthread_mutexattr_t ma;
|
||||
check( pthread_mutexattr_init(&ma) );
|
||||
check( pthread_mutex_init(&mutPrintf, &ma) );
|
||||
```
|
||||
|
||||
and replaced all instances of `check_errno( sem_wait(&semPrintf) );` with `check( pthread_mutex_lock(&mutPrintf) );` and `check_errno( sem_post(&semPrintf) );` with `check( pthread_mutex_unlock(&mutPrintf) );`. as last removed the `sem_destroy` call.
|
||||
|
||||
The final code is available at [/report-2/week_1.5/assignment_5.3/main.c](https://git.gay/LailaTheElf/RTS10_reports/src/branch/main/report-2/week_1.5/assignment_5.3/main.c)
|
||||
|
||||
the code work the same as before.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
187
report-2/week_1.5/assignment_5.2/main.c
Normal file
187
report-2/week_1.5/assignment_5.2/main.c
Normal file
@ -0,0 +1,187 @@
|
||||
#include "main.h"
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <mqueue.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define SIZE 8
|
||||
|
||||
void check_errno(int error)
|
||||
{
|
||||
if (error < 0)
|
||||
{
|
||||
perror("Error");
|
||||
while (1);
|
||||
}
|
||||
}
|
||||
|
||||
void check(int error)
|
||||
{
|
||||
if (error != 0)
|
||||
{
|
||||
printf("Error: %s\n", strerror(error));
|
||||
while (1);
|
||||
}
|
||||
}
|
||||
|
||||
mqd_t mqFood;
|
||||
sem_t semPrintf;
|
||||
|
||||
void put(char c)
|
||||
{
|
||||
check_errno( mq_send(mqFood, (char *)&c, sizeof(c), 0) );
|
||||
}
|
||||
|
||||
char get(void)
|
||||
{
|
||||
char c = 0;
|
||||
check_errno( mq_receive(mqFood, (char *)&c, sizeof(c), NULL) );
|
||||
return c;
|
||||
}
|
||||
|
||||
void *producer(void *arg) // function for producer thread
|
||||
{
|
||||
char c = *(char *)arg;
|
||||
check_errno( sem_wait(&semPrintf) );
|
||||
check_errno( printf("Thread: %p with argument: %c starts\n", pthread_self(), c) );
|
||||
check_errno( sem_post(&semPrintf) );
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
put(c);
|
||||
}
|
||||
check_errno( sem_wait(&semPrintf) );
|
||||
check_errno( printf("Thread: %p stops\n", pthread_self()) );
|
||||
check_errno( sem_post(&semPrintf) );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *consumer(void *arg) // function for consumer thread
|
||||
{
|
||||
check_errno( sem_wait(&semPrintf) );
|
||||
check_errno( printf("Thread: %p starts\n", pthread_self()) );
|
||||
check_errno( sem_post(&semPrintf) );
|
||||
for (int i = 0; i < 200; ++i)
|
||||
{
|
||||
char c = get();
|
||||
check_errno( sem_wait(&semPrintf) );
|
||||
check_errno( printf("%c", c) );
|
||||
check_errno( fflush(stdout) );
|
||||
check_errno( sem_post(&semPrintf) );
|
||||
}
|
||||
check_errno( sem_wait(&semPrintf) );
|
||||
check_errno( printf("Thread: %p stops\n", pthread_self()) );
|
||||
check_errno( sem_post(&semPrintf) );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int read_prio(char *process_name)
|
||||
{
|
||||
int prio;
|
||||
do
|
||||
{
|
||||
check_errno( printf("Enter priority for process %s [1..15]: ", process_name) );
|
||||
check_errno( fflush(stdout) );
|
||||
}
|
||||
while (scanf("%d", &prio) != 1 || prio < 1 || prio > 15);
|
||||
return prio;
|
||||
}
|
||||
|
||||
void *main_thread(void *arg)
|
||||
{
|
||||
int prioc = read_prio("Consumer");
|
||||
int priop1 = read_prio("Frikandel Producer");
|
||||
int priop2 = read_prio("Kroket Producer");
|
||||
|
||||
check_errno( printf("Output for Consumer priority = %d ", prioc) );
|
||||
check_errno( printf("frikandel Producer priority = %d ", priop1) );
|
||||
check_errno( printf("Kroket Producer priority = %d\n", priop2) );
|
||||
|
||||
check_errno( sem_init(&semPrintf, 0, 1) ); // allow one thread exclusively to use printf
|
||||
|
||||
// Zie UM2609 6.2.1.2 Add to registry
|
||||
// https://www.st.com/resource/en/user_manual/dm00629856-stm32cubeide-user-guide-stmicroelectronics.pdf
|
||||
vQueueAddToRegistry((QueueHandle_t) &semPrintf.xSemaphore, "semPrintf");
|
||||
|
||||
struct mq_attr mqAttrs;
|
||||
mqAttrs.mq_maxmsg = SIZE;
|
||||
mqAttrs.mq_msgsize = sizeof(char);
|
||||
mqAttrs.mq_flags = 0;
|
||||
check_errno((int)( mqFood = mq_open("/food", O_RDWR | O_CREAT, 0666, &mqAttrs) ));
|
||||
|
||||
pthread_attr_t ptac, ptap1, ptap2;
|
||||
check( pthread_attr_init(&ptac) );
|
||||
check( pthread_attr_init(&ptap1) );
|
||||
check( pthread_attr_init(&ptap2) );
|
||||
|
||||
check( pthread_attr_setstacksize(&ptac, 1024) );
|
||||
check( pthread_attr_setstacksize(&ptap1, 1024) );
|
||||
check( pthread_attr_setstacksize(&ptap2, 1024) );
|
||||
|
||||
struct sched_param spc, spp1, spp2;
|
||||
check( pthread_attr_getschedparam(&ptac, &spc) );
|
||||
check( pthread_attr_getschedparam(&ptap1, &spp1) );
|
||||
check( pthread_attr_getschedparam(&ptap2, &spp2) );
|
||||
|
||||
spc.sched_priority = prioc;
|
||||
spp1.sched_priority = priop1;
|
||||
spp2.sched_priority = priop2;
|
||||
|
||||
check( pthread_attr_setschedparam(&ptac, &spc) );
|
||||
check( pthread_attr_setschedparam(&ptap1, &spp1) );
|
||||
check( pthread_attr_setschedparam(&ptap2, &spp2) );
|
||||
|
||||
pthread_t ptc, ptp1, ptp2;
|
||||
char frikandel = 'F', kroket = 'K';
|
||||
check( pthread_create(&ptc, &ptac, consumer, NULL) );
|
||||
check( pthread_create(&ptp1, &ptap1, producer, &frikandel) );
|
||||
check( pthread_create(&ptp2, &ptap2, producer, &kroket) );
|
||||
|
||||
check( pthread_join(ptc, NULL) );
|
||||
check( pthread_join(ptp1, NULL) );
|
||||
check( pthread_join(ptp2, NULL) );
|
||||
|
||||
check_errno( sem_destroy(&semPrintf) );
|
||||
|
||||
check( mq_close(mqFood) );
|
||||
check( mq_unlink("/food") );
|
||||
|
||||
check( pthread_attr_destroy(&ptac) );
|
||||
check( pthread_attr_destroy(&ptap1) );
|
||||
check( pthread_attr_destroy(&ptap2) );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Board_Init();
|
||||
|
||||
pthread_attr_t pta;
|
||||
check( pthread_attr_init(&pta) );
|
||||
check( pthread_attr_setdetachstate(&pta, PTHREAD_CREATE_DETACHED) );
|
||||
check( pthread_attr_setstacksize(&pta, 1024) );
|
||||
|
||||
struct sched_param sp;
|
||||
check( pthread_attr_getschedparam(&pta, &sp) );
|
||||
// The main thread must have the highest priority because this thread will start
|
||||
// the other threads and we want to study the interaction between those other threads
|
||||
sp.sched_priority = 15;
|
||||
check( pthread_attr_setschedparam(&pta, &sp) );
|
||||
|
||||
pthread_t pt;
|
||||
check( pthread_create(&pt, &pta, main_thread, NULL) );
|
||||
|
||||
printf("\n");
|
||||
vTaskStartScheduler();
|
||||
/* We should never get here as control is now taken by the scheduler */
|
||||
|
||||
check( pthread_attr_destroy(&pta) );
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
183
report-2/week_1.5/assignment_5.3/main.c
Normal file
183
report-2/week_1.5/assignment_5.3/main.c
Normal file
@ -0,0 +1,183 @@
|
||||
#include "main.h"
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <mqueue.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define SIZE 8
|
||||
|
||||
void check_errno(int error)
|
||||
{
|
||||
if (error < 0)
|
||||
{
|
||||
perror("Error");
|
||||
while (1);
|
||||
}
|
||||
}
|
||||
|
||||
void check(int error)
|
||||
{
|
||||
if (error != 0)
|
||||
{
|
||||
printf("Error: %s\n", strerror(error));
|
||||
while (1);
|
||||
}
|
||||
}
|
||||
|
||||
mqd_t mqFood;
|
||||
pthread_mutex_t mutPrintf;
|
||||
|
||||
void put(char c)
|
||||
{
|
||||
check_errno( mq_send(mqFood, (char *)&c, sizeof(c), 0) );
|
||||
}
|
||||
|
||||
char get(void)
|
||||
{
|
||||
char c = 0;
|
||||
check_errno( mq_receive(mqFood, (char *)&c, sizeof(c), NULL) );
|
||||
return c;
|
||||
}
|
||||
|
||||
void *producer(void *arg) // function for producer thread
|
||||
{
|
||||
char c = *(char *)arg;
|
||||
check( pthread_mutex_lock(&mutPrintf) );
|
||||
check_errno( printf("Thread: %p with argument: %c starts\n", pthread_self(), c) );
|
||||
check( pthread_mutex_unlock(&mutPrintf) );
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
put(c);
|
||||
}
|
||||
check( pthread_mutex_lock(&mutPrintf) );
|
||||
check_errno( printf("Thread: %p stops\n", pthread_self()) );
|
||||
check( pthread_mutex_unlock(&mutPrintf) );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *consumer(void *arg) // function for consumer thread
|
||||
{
|
||||
check( pthread_mutex_lock(&mutPrintf) );
|
||||
check_errno( printf("Thread: %p starts\n", pthread_self()) );
|
||||
check( pthread_mutex_unlock(&mutPrintf) );
|
||||
for (int i = 0; i < 200; ++i)
|
||||
{
|
||||
char c = get();
|
||||
check( pthread_mutex_lock(&mutPrintf) );
|
||||
check_errno( printf("%c", c) );
|
||||
check_errno( fflush(stdout) );
|
||||
check( pthread_mutex_unlock(&mutPrintf) );
|
||||
}
|
||||
check( pthread_mutex_lock(&mutPrintf) );
|
||||
check_errno( printf("Thread: %p stops\n", pthread_self()) );
|
||||
check( pthread_mutex_unlock(&mutPrintf) );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int read_prio(char *process_name)
|
||||
{
|
||||
int prio;
|
||||
do
|
||||
{
|
||||
check_errno( printf("Enter priority for process %s [1..15]: ", process_name) );
|
||||
check_errno( fflush(stdout) );
|
||||
}
|
||||
while (scanf("%d", &prio) != 1 || prio < 1 || prio > 15);
|
||||
return prio;
|
||||
}
|
||||
|
||||
void *main_thread(void *arg)
|
||||
{
|
||||
int prioc = read_prio("Consumer");
|
||||
int priop1 = read_prio("Frikandel Producer");
|
||||
int priop2 = read_prio("Kroket Producer");
|
||||
|
||||
check_errno( printf("Output for Consumer priority = %d ", prioc) );
|
||||
check_errno( printf("frikandel Producer priority = %d ", priop1) );
|
||||
check_errno( printf("Kroket Producer priority = %d\n", priop2) );
|
||||
|
||||
pthread_mutexattr_t ma;
|
||||
check( pthread_mutexattr_init(&ma) );
|
||||
check( pthread_mutex_init(&mutPrintf, &ma) );
|
||||
|
||||
struct mq_attr mqAttrs;
|
||||
mqAttrs.mq_maxmsg = SIZE;
|
||||
mqAttrs.mq_msgsize = sizeof(char);
|
||||
mqAttrs.mq_flags = 0;
|
||||
check_errno((int)( mqFood = mq_open("/food", O_RDWR | O_CREAT, 0666, &mqAttrs) ));
|
||||
|
||||
pthread_attr_t ptac, ptap1, ptap2;
|
||||
check( pthread_attr_init(&ptac) );
|
||||
check( pthread_attr_init(&ptap1) );
|
||||
check( pthread_attr_init(&ptap2) );
|
||||
|
||||
check( pthread_attr_setstacksize(&ptac, 1024) );
|
||||
check( pthread_attr_setstacksize(&ptap1, 1024) );
|
||||
check( pthread_attr_setstacksize(&ptap2, 1024) );
|
||||
|
||||
struct sched_param spc, spp1, spp2;
|
||||
check( pthread_attr_getschedparam(&ptac, &spc) );
|
||||
check( pthread_attr_getschedparam(&ptap1, &spp1) );
|
||||
check( pthread_attr_getschedparam(&ptap2, &spp2) );
|
||||
|
||||
spc.sched_priority = prioc;
|
||||
spp1.sched_priority = priop1;
|
||||
spp2.sched_priority = priop2;
|
||||
|
||||
check( pthread_attr_setschedparam(&ptac, &spc) );
|
||||
check( pthread_attr_setschedparam(&ptap1, &spp1) );
|
||||
check( pthread_attr_setschedparam(&ptap2, &spp2) );
|
||||
|
||||
pthread_t ptc, ptp1, ptp2;
|
||||
char frikandel = 'F', kroket = 'K';
|
||||
check( pthread_create(&ptc, &ptac, consumer, NULL) );
|
||||
check( pthread_create(&ptp1, &ptap1, producer, &frikandel) );
|
||||
check( pthread_create(&ptp2, &ptap2, producer, &kroket) );
|
||||
|
||||
check( pthread_join(ptc, NULL) );
|
||||
check( pthread_join(ptp1, NULL) );
|
||||
check( pthread_join(ptp2, NULL) );
|
||||
|
||||
check( mq_close(mqFood) );
|
||||
check( mq_unlink("/food") );
|
||||
|
||||
check( pthread_attr_destroy(&ptac) );
|
||||
check( pthread_attr_destroy(&ptap1) );
|
||||
check( pthread_attr_destroy(&ptap2) );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Board_Init();
|
||||
|
||||
pthread_attr_t pta;
|
||||
check( pthread_attr_init(&pta) );
|
||||
check( pthread_attr_setdetachstate(&pta, PTHREAD_CREATE_DETACHED) );
|
||||
check( pthread_attr_setstacksize(&pta, 1024) );
|
||||
|
||||
struct sched_param sp;
|
||||
check( pthread_attr_getschedparam(&pta, &sp) );
|
||||
// The main thread must have the highest priority because this thread will start
|
||||
// the other threads and we want to study the interaction between those other threads
|
||||
sp.sched_priority = 15;
|
||||
check( pthread_attr_setschedparam(&pta, &sp) );
|
||||
|
||||
pthread_t pt;
|
||||
check( pthread_create(&pt, &pta, main_thread, NULL) );
|
||||
|
||||
printf("\n");
|
||||
vTaskStartScheduler();
|
||||
/* We should never get here as control is now taken by the scheduler */
|
||||
|
||||
check( pthread_attr_destroy(&pta) );
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user