add: assigment 2
This commit is contained in:
parent
3a0b8a5c3f
commit
32a6e07e56
11 changed files with 437 additions and 0 deletions
88
assignment2/part3/consumer.c
Normal file
88
assignment2/part3/consumer.c
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <time.h>
|
||||
|
||||
volatile sig_atomic_t shutdown_flag = 0;
|
||||
volatile sig_atomic_t stats_flag = 0;
|
||||
|
||||
void handle_sigint(int sig) {
|
||||
shutdown_flag = 1;
|
||||
}
|
||||
|
||||
void handle_sigusr1(int sig) {
|
||||
stats_flag = 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct sigaction sa_sigint;
|
||||
sa_sigint.sa_handler = handle_sigint;
|
||||
sigemptyset(&sa_sigint.sa_mask);
|
||||
sa_sigint.sa_flags = 0;
|
||||
sigaction(SIGINT, &sa_sigint, NULL);
|
||||
|
||||
struct sigaction sa_sigusr1;
|
||||
sa_sigusr1.sa_handler = handle_sigusr1;
|
||||
sigemptyset(&sa_sigusr1.sa_mask);
|
||||
sa_sigusr1.sa_flags = 0;
|
||||
sigaction(SIGUSR1, &sa_sigusr1, NULL);
|
||||
|
||||
int max_lines = -1; // -1 means unlimited
|
||||
int verbose = 0;
|
||||
|
||||
// Parse arguments (-n max_lines, -v verbose)
|
||||
char opt;
|
||||
while ((opt = getopt(argc, argv, "n:v")) != -1) {
|
||||
switch (opt) {
|
||||
case 'n':
|
||||
max_lines = atoi(optarg); break;
|
||||
case 'v':
|
||||
verbose = 1; break;
|
||||
default:
|
||||
printf("Usage: %s [-n max_lines] [-v]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
clock_t start = clock();
|
||||
|
||||
// Read from stdin line by line
|
||||
// Count lines and characters
|
||||
// If verbose, echo lines to stdout
|
||||
char buffer[256];
|
||||
int lines = 0;
|
||||
int chars = 0;
|
||||
while (fgets(buffer, sizeof(buffer), stdin) != NULL) {
|
||||
int size = strlen(buffer);
|
||||
if (verbose)
|
||||
fwrite(buffer, sizeof(char), size, stdout);
|
||||
chars += size;
|
||||
if (size > 0 && buffer[size - 1] == '\n')
|
||||
lines++;
|
||||
if (lines == max_lines)
|
||||
break;
|
||||
|
||||
// Handle shutdown
|
||||
if (shutdown_flag) {
|
||||
fprintf(stderr, "Cancelled\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Print statistics to stderr (handle SIGUSR1)
|
||||
if (stats_flag) {
|
||||
clock_t end = clock();
|
||||
double time = ((double)(end - start)) / CLOCKS_PER_SEC;
|
||||
double throughput = (double)chars / 1024.0 / 1024.0 / time;
|
||||
printf("Stats:\n");
|
||||
printf("File Size: %d bytes\n", chars);
|
||||
printf("Total Time: %.3f secs\n", time);
|
||||
printf("Throughput: %.3f MB/s\n", throughput);
|
||||
}
|
||||
fprintf(stderr, "Lines: %d\n", lines);
|
||||
|
||||
return 0;
|
||||
}
|
||||
63
assignment2/part3/producer.c
Normal file
63
assignment2/part3/producer.c
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
|
||||
volatile sig_atomic_t shutdown_flag = 0;
|
||||
|
||||
void handle_sigint(int sig) {
|
||||
shutdown_flag = 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = handle_sigint;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
|
||||
FILE *input = stdin;
|
||||
int buffer_size = 4096;
|
||||
|
||||
// Parse command line arguments
|
||||
// -f filename (optional)
|
||||
// b buffer_size (optional)
|
||||
char opt;
|
||||
while ((opt = getopt(argc, argv, "f:b:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
input = fopen(optarg, "r");
|
||||
if (input == NULL) {
|
||||
fprintf(stderr, "Error: Could not open input file\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
buffer_size = atoi(optarg); break;
|
||||
default:
|
||||
printf("Usage: %s [-f filename] [-b buffer_size]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate buffer
|
||||
char *buffer = malloc(buffer_size);
|
||||
|
||||
// Read from input and write to stdout
|
||||
while (fgets(buffer, buffer_size, input) != NULL) {
|
||||
fwrite(buffer, sizeof(char), strlen(buffer), stdout);
|
||||
|
||||
// Handle shutdown
|
||||
if (shutdown_flag) {
|
||||
fprintf(stderr, "Cancelled\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
free(buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
33
assignment2/part3/test
Executable file
33
assignment2/part3/test
Executable file
|
|
@ -0,0 +1,33 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
echo "Building executables..."
|
||||
|
||||
cd "${FLAKE:-$(dirname $0)}"
|
||||
if command -v nix; then
|
||||
producer="$(nix build --no-link --print-out-paths .#a2-p3-producer)/bin/producer"
|
||||
consumer="$(nix build --no-link --print-out-paths .#a2-p3-consumer)/bin/consumer"
|
||||
else
|
||||
gcc producer.c -o producer
|
||||
gcc consumer.c -o consumer
|
||||
producer="./producer"
|
||||
consumer="./consumer"
|
||||
fi
|
||||
|
||||
seq 1 10000000 >large.txt
|
||||
|
||||
echo -e "\nTEST - Buffer size 1024"
|
||||
"$producer" -b 1024 -f large.txt | "$consumer" &
|
||||
kill -USR1 "$(pidof consumer)"
|
||||
wait "$(jobs -rp)"
|
||||
|
||||
echo -e "\nTEST - Buffer size 4096"
|
||||
"$producer" -b 4096 -f large.txt | "$consumer" &
|
||||
kill -USR1 "$(pidof consumer)"
|
||||
wait "$(jobs -rp)"
|
||||
|
||||
echo -e "\nTEST - Buffer size 16384"
|
||||
"$producer" -b 16384 -f large.txt | "$consumer" &
|
||||
kill -USR1 "$(pidof consumer)"
|
||||
wait "$(jobs -rp)"
|
||||
|
||||
rm large.txt
|
||||
Loading…
Add table
Add a link
Reference in a new issue