Create 5
This commit is contained in:
1 parent
66d309b937
commit
a245043da0
6 files changed
+569
No files matched your search
@@ -0,0 +1,160 @@
|
||||
// consumer.c
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <semaphore.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <float.h> // For FLT_MAX, FLT_MIN (or DBL_MAX etc.)
|
||||
#include <signal.h> // For signal handling
|
||||
|
||||
#include "data_structures.h" // Common header
|
||||
|
||||
SharedData *shared_data_ptr = NULL;
|
||||
int shm_fd = -1;
|
||||
sem_t *mutex_sem = SEM_FAILED;
|
||||
volatile sig_atomic_t keep_running = 1;
|
||||
|
||||
void cleanup_ipc_consumer() {
|
||||
printf("\nConsumer cleaning up...\n");
|
||||
if (shared_data_ptr != MAP_FAILED && shared_data_ptr != NULL) {
|
||||
if (munmap(shared_data_ptr, sizeof(SharedData)) == -1) {
|
||||
perror("munmap");
|
||||
}
|
||||
}
|
||||
if (shm_fd != -1) {
|
||||
close(shm_fd);
|
||||
// Consumer does NOT unlink shared memory, producer owns it
|
||||
}
|
||||
if (mutex_sem != SEM_FAILED) {
|
||||
sem_close(mutex_sem);
|
||||
// Consumer does NOT unlink semaphore, producer owns it
|
||||
}
|
||||
printf("Consumer cleanup complete.\n");
|
||||
}
|
||||
|
||||
void sigint_handler_consumer(int sig) {
|
||||
printf("\nConsumer received SIGINT. Shutting down...\n");
|
||||
keep_running = 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = sigint_handler_consumer;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
if (sigaction(SIGINT, &sa, NULL) == -1) {
|
||||
perror("sigaction");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (sigaction(SIGTERM, &sa, NULL) == -1) {
|
||||
perror("sigaction for SIGTERM");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// 1. Open existing POSIX shared memory object (DO NOT CREATE)
|
||||
shm_fd = shm_open(SHM_NAME, O_RDWR, 0666); // O_RDONLY if only reading
|
||||
if (shm_fd == -1) {
|
||||
perror("shm_open (Is the producer.c program running?)");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// 2. Map the shared memory object into the process's address space
|
||||
// Note: Size is known from SharedData struct. ftruncate is not needed here.
|
||||
shared_data_ptr = mmap(0, sizeof(SharedData), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); // PROT_READ if only reading
|
||||
if (shared_data_ptr == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
close(shm_fd);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
printf("Shared memory opened and mapped successfully.\n");
|
||||
|
||||
// 3. Open existing POSIX named semaphore (DO NOT CREATE)
|
||||
mutex_sem = sem_open(SEM_MUTEX_NAME, 0); // Flags argument is 0 when opening existing
|
||||
if (mutex_sem == SEM_FAILED) {
|
||||
perror("sem_open (Is the producer.c program running and semaphore created?)");
|
||||
munmap(shared_data_ptr, sizeof(SharedData));
|
||||
close(shm_fd);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
printf("Mutex semaphore opened successfully.\n");
|
||||
|
||||
printf("Monitoring room display started. Press Ctrl+C to exit.\n");
|
||||
printf("Will display data every %d seconds.\n\n", MONITOR_DISPLAY_INTERVAL);
|
||||
|
||||
// 4. Monitoring loop
|
||||
while (keep_running) {
|
||||
// Wait for semaphore
|
||||
if (sem_wait(mutex_sem) == -1) {
|
||||
if (keep_running)
|
||||
perror("sem_wait in consumer"); // Don't print error if shutting down
|
||||
break; // Exit loop on error or interruption
|
||||
}
|
||||
|
||||
float max_temp = -FLT_MAX;
|
||||
float min_temp = FLT_MAX;
|
||||
int hottest_workshop_idx = -1;
|
||||
int coldest_workshop_idx = -1;
|
||||
int valid_data_found = 0;
|
||||
|
||||
for (int i = 0; i < NUM_WORKSHOPS; ++i) {
|
||||
// Check if the workshop data looks initialized (not default 0.0 or some other sentinel)
|
||||
// For this example, any non-zero temp can be considered, or rely on producer to fill.
|
||||
// A more robust way would be a 'valid' flag per workshop or timestamp.
|
||||
if (shared_data_ptr->workshops[i].temperature != 0.0f || shared_data_ptr->workshops[i].humidity != 0.0f) {
|
||||
valid_data_found = 1; // At least one workshop has some data
|
||||
}
|
||||
|
||||
float current_temp = shared_data_ptr->workshops[i].temperature;
|
||||
|
||||
if (current_temp > max_temp) {
|
||||
max_temp = current_temp;
|
||||
hottest_workshop_idx = i;
|
||||
}
|
||||
if (current_temp < min_temp) {
|
||||
min_temp = current_temp;
|
||||
coldest_workshop_idx = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Release semaphore
|
||||
if (sem_post(mutex_sem) == -1) {
|
||||
perror("sem_post in consumer");
|
||||
break; // Exit loop on error
|
||||
}
|
||||
|
||||
// Display data
|
||||
if (hottest_workshop_idx != -1 && coldest_workshop_idx != -1 && valid_data_found) {
|
||||
printf("--- Monitoring Update (%s", ctime(&(time_t){ time(NULL) })); // ctime adds newline
|
||||
printf(" Highest Temp: Workshop %d (%.2f C, %.2f %% Humidity)\n",
|
||||
shared_data_ptr->workshops[hottest_workshop_idx].workshop_id,
|
||||
max_temp,
|
||||
shared_data_ptr->workshops[hottest_workshop_idx].humidity);
|
||||
printf(" Lowest Temp: Workshop %d (%.2f C, %.2f %% Humidity)\n",
|
||||
shared_data_ptr->workshops[coldest_workshop_idx].workshop_id,
|
||||
min_temp,
|
||||
shared_data_ptr->workshops[coldest_workshop_idx].humidity);
|
||||
printf("---\n\n");
|
||||
}
|
||||
else if (!valid_data_found) {
|
||||
printf("[%s] Waiting for initial data from workshops...\n\n", ctime(&(time_t){ time(NULL) }));
|
||||
}
|
||||
else {
|
||||
printf("[%s] No valid temperature extremes found yet (all workshops might have same temp or no data).\n\n", ctime(&(time_t){ time(NULL) }));
|
||||
}
|
||||
fflush(stdout);
|
||||
|
||||
// Sleep for the display interval
|
||||
for (int i = 0; i < MONITOR_DISPLAY_INTERVAL && keep_running; ++i) {
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Cleanup: Unmap shared memory, close file descriptor, close semaphore
|
||||
cleanup_ipc_consumer();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// data_structures.h
|
||||
#ifndef DATA_STRUCTURES_H
|
||||
#define DATA_STRUCTURES_H
|
||||
|
||||
#include <pthread.h> // For pthread_t, though not strictly needed in Program 2 if monitor is in main
|
||||
#include <semaphore.h> // For sem_t
|
||||
#include <time.h> // For time_t (optional)
|
||||
|
||||
#define NUM_WORKSHOPS 10
|
||||
#define SHM_NAME "/workshop_monitoring_shm"
|
||||
#define SEM_MUTEX_NAME "/workshop_monitoring_mutex_sem"
|
||||
|
||||
// Min/Max values for simulation
|
||||
#define MIN_TEMP 10.0f
|
||||
#define MAX_TEMP 40.0f
|
||||
#define MIN_HUMIDITY 20.0f
|
||||
#define MAX_HUMIDITY 80.0f
|
||||
|
||||
// Interval for workshop data generation (seconds)
|
||||
#define WORKSHOP_UPDATE_INTERVAL 2
|
||||
// Interval for monitoring display (seconds)
|
||||
#define MONITOR_DISPLAY_INTERVAL 5
|
||||
|
||||
typedef struct {
|
||||
int workshop_id;
|
||||
float temperature;
|
||||
float humidity;
|
||||
// time_t last_updated; // Optional: timestamp of last update
|
||||
} WorkshopData;
|
||||
|
||||
typedef struct {
|
||||
WorkshopData workshops[NUM_WORKSHOPS];
|
||||
// Could add a generation counter or other metadata if needed
|
||||
// int data_ready_count; // Could be used with condition variables if within one process
|
||||
} SharedData;
|
||||
|
||||
#endif // DATA_STRUCTURES_H
|
||||
@@ -0,0 +1,73 @@
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// Shared variables
|
||||
int total_count = 0;
|
||||
int even_count = 0;
|
||||
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
bool running = true;
|
||||
|
||||
// Thread to report total count every 3 seconds
|
||||
void* report_total(void* arg) {
|
||||
while(running) {
|
||||
sleep(3);
|
||||
pthread_mutex_lock(&mutex);
|
||||
printf("Total numbers entered so far: %d\n", total_count);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Thread to report even count every 5 seconds
|
||||
void* report_even(void* arg) {
|
||||
while(running) {
|
||||
sleep(5);
|
||||
pthread_mutex_lock(&mutex);
|
||||
printf("Total even numbers entered so far: %d\n", even_count);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main() {
|
||||
pthread_t total_thread, even_thread;
|
||||
int num;
|
||||
|
||||
// Create the reporting threads
|
||||
pthread_create(&total_thread, NULL, report_total, NULL);
|
||||
pthread_create(&even_thread, NULL, report_even, NULL);
|
||||
|
||||
printf("Enter integers (enter a negative number to exit):\n");
|
||||
|
||||
while(1) {
|
||||
scanf("%d", &num);
|
||||
|
||||
if(num < 0) {
|
||||
printf("Negative number entered. Exiting program.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&mutex);
|
||||
total_count++;
|
||||
|
||||
if(num % 2 == 0) {
|
||||
even_count++;
|
||||
printf("%d is an even number.\n", num);
|
||||
} else {
|
||||
printf("%d is an odd number.\n", num);
|
||||
}
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
// Signal threads to terminate and wait for them
|
||||
running = false;
|
||||
pthread_join(total_thread, NULL);
|
||||
pthread_join(even_thread, NULL);
|
||||
|
||||
pthread_mutex_destroy(&mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
// producer.c
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <semaphore.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <signal.h> // For signal handling
|
||||
#include <float.h> // For FLT_MAX etc. (not strictly needed here but good for min/max init)
|
||||
#include <stdint.h> // For intptr_t
|
||||
|
||||
#include "data_structures.h" // Common header
|
||||
|
||||
SharedData *shared_data_ptr = NULL;
|
||||
int shm_fd = -1;
|
||||
sem_t *mutex_sem = SEM_FAILED;
|
||||
pthread_t workshop_threads[NUM_WORKSHOPS];
|
||||
volatile sig_atomic_t keep_running = 1;
|
||||
|
||||
void cleanup_ipc() {
|
||||
printf("\nProducer cleaning up IPC...\n");
|
||||
if (shared_data_ptr != MAP_FAILED && shared_data_ptr != NULL) {
|
||||
if (munmap(shared_data_ptr, sizeof(SharedData)) == -1) {
|
||||
perror("munmap");
|
||||
}
|
||||
}
|
||||
if (shm_fd != -1) {
|
||||
close(shm_fd);
|
||||
if (shm_unlink(SHM_NAME) == -1) {
|
||||
// perror("shm_unlink"); // Might have been unlinked by another instance or if it never fully started
|
||||
}
|
||||
}
|
||||
if (mutex_sem != SEM_FAILED) {
|
||||
sem_close(mutex_sem);
|
||||
if (sem_unlink(SEM_MUTEX_NAME) == -1) {
|
||||
// perror("sem_unlink"); // Similar to shm_unlink
|
||||
}
|
||||
}
|
||||
printf("Producer IPC cleanup complete.\n");
|
||||
}
|
||||
|
||||
void sigint_handler(int sig) {
|
||||
printf("\nProducer received SIGINT. Shutting down...\n");
|
||||
keep_running = 0;
|
||||
// Give threads a moment to notice keep_running flag
|
||||
// In a more robust system, you'd signal threads to exit using pthread_cancel or condition variables.
|
||||
// For this example, they will check keep_running.
|
||||
}
|
||||
|
||||
// Function for each workshop thread
|
||||
void *workshop_thread_func(void *arg) {
|
||||
int workshop_id = (int)(intptr_t)arg; // Safer than &i from main loop
|
||||
srand(time(NULL) ^ pthread_self()); // Seed random number generator per thread
|
||||
|
||||
printf("Workshop thread %d started.\n", workshop_id);
|
||||
|
||||
while (keep_running) {
|
||||
// Simulate data generation
|
||||
float current_temp = MIN_TEMP + ((float)rand() / RAND_MAX) * (MAX_TEMP - MIN_TEMP);
|
||||
float current_humidity = MIN_HUMIDITY + ((float)rand() / RAND_MAX) * (MAX_HUMIDITY - MIN_HUMIDITY);
|
||||
|
||||
// Acquire semaphore
|
||||
if (sem_wait(mutex_sem) == -1) {
|
||||
perror("sem_wait in workshop thread");
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
// Write data to shared memory
|
||||
shared_data_ptr->workshops[workshop_id].temperature = current_temp;
|
||||
shared_data_ptr->workshops[workshop_id].humidity = current_humidity;
|
||||
// shared_data_ptr->workshops[workshop_id].last_updated = time(NULL); // Optional
|
||||
|
||||
printf("Workshop %d: Temp = %.2f C, Humidity = %.2f %%\n",
|
||||
workshop_id, current_temp, current_humidity);
|
||||
|
||||
// Release semaphore
|
||||
if (sem_post(mutex_sem) == -1) {
|
||||
perror("sem_post in workshop thread");
|
||||
// Continue, but this is problematic
|
||||
}
|
||||
|
||||
// Sleep for a while
|
||||
for (int i = 0; i < WORKSHOP_UPDATE_INTERVAL && keep_running; ++i) {
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Workshop thread %d exiting.\n", workshop_id);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
int main() {
|
||||
// Register signal handler for Ctrl+C
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = sigint_handler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0; // or SA_RESTART to restart syscalls if interrupted by this signal
|
||||
if (sigaction(SIGINT, &sa, NULL) == -1) {
|
||||
perror("sigaction");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (sigaction(SIGTERM, &sa, NULL) == -1) {
|
||||
perror("sigaction for SIGTERM");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// 1. Create or open POSIX shared memory object
|
||||
// O_EXCL can be used to ensure we are the first to create it,
|
||||
// but for robust restart, we might remove it and handle existing SHM.
|
||||
// For this assignment, let's assume clean startup.
|
||||
shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR | O_EXCL, 0666);
|
||||
if (shm_fd == -1) {
|
||||
perror("shm_open (Is another producer instance running or /dev/shm full?)");
|
||||
// Attempt to open if it already exists (for cleanup or if O_EXCL was removed)
|
||||
shm_fd = shm_open(SHM_NAME, O_RDWR, 0666);
|
||||
if (shm_fd == -1) {
|
||||
perror("shm_open (secondary attempt)");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
// If opened existing, we might not want to ftruncate, but for a fresh start this is okay
|
||||
// Or better, unlink first if it exists from a previous bad run.
|
||||
printf("Warning: Shared memory %s already existed. Unlinking and recreating.\n", SHM_NAME);
|
||||
shm_unlink(SHM_NAME); // Clean up if it exists
|
||||
shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0666);
|
||||
if (shm_fd == -1) {
|
||||
perror("shm_open (after unlink)");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Set the size of the shared memory object
|
||||
if (ftruncate(shm_fd, sizeof(SharedData)) == -1) {
|
||||
perror("ftruncate");
|
||||
close(shm_fd);
|
||||
shm_unlink(SHM_NAME); // Clean up
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// 3. Map the shared memory object into the process's address space
|
||||
shared_data_ptr = mmap(0, sizeof(SharedData), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
|
||||
if (shared_data_ptr == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
close(shm_fd);
|
||||
shm_unlink(SHM_NAME); // Clean up
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
printf("Shared memory created/opened and mapped successfully.\n");
|
||||
|
||||
// Initialize workshop IDs and default data
|
||||
for (int i = 0; i < NUM_WORKSHOPS; ++i) {
|
||||
shared_data_ptr->workshops[i].workshop_id = i;
|
||||
shared_data_ptr->workshops[i].temperature = 0.0f; // Initial value
|
||||
shared_data_ptr->workshops[i].humidity = 0.0f; // Initial value
|
||||
}
|
||||
|
||||
// 4. Create or open a POSIX named semaphore (acting as a mutex)
|
||||
// O_EXCL can be used here as well for similar reasons to shm_open.
|
||||
mutex_sem = sem_open(SEM_MUTEX_NAME, O_CREAT | O_EXCL, 0666, 1); // Initial value 1 (unlocked)
|
||||
if (mutex_sem == SEM_FAILED) {
|
||||
perror("sem_open (Is another producer instance running with this semaphore?)");
|
||||
sem_unlink(SEM_MUTEX_NAME); // Attempt to clean up if it exists
|
||||
mutex_sem = sem_open(SEM_MUTEX_NAME, O_CREAT, 0666, 1);
|
||||
if (mutex_sem == SEM_FAILED) {
|
||||
perror("sem_open (after unlink)");
|
||||
cleanup_ipc(); // Full cleanup
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
printf("Warning: Semaphore %s already existed. Unlinking and recreating.\n", SEM_MUTEX_NAME);
|
||||
}
|
||||
printf("Mutex semaphore created/opened successfully.\n");
|
||||
|
||||
// Seed random number generator for main (primarily for workshop thread seeding)
|
||||
srand(time(NULL));
|
||||
|
||||
// 5. Create workshop threads
|
||||
printf("Creating %d workshop threads...\n", NUM_WORKSHOPS);
|
||||
for (long i = 0; i < NUM_WORKSHOPS; ++i) {
|
||||
// Note: Casting 'i' to void* and back to int (via intptr_t) is a common shorthand
|
||||
// for passing small integer IDs. For complex arguments, a struct pointer is better.
|
||||
if (pthread_create(&workshop_threads[i], NULL, workshop_thread_func, (void *)i) != 0) {
|
||||
perror("pthread_create");
|
||||
keep_running = 0; // Signal other threads to stop
|
||||
// Join already created threads before exiting
|
||||
for (long j = 0; j < i; ++j) {
|
||||
pthread_join(workshop_threads[j], NULL);
|
||||
}
|
||||
cleanup_ipc();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
printf("All workshop threads created. Producer is running. Press Ctrl+C to exit.\n");
|
||||
|
||||
// Keep the main thread alive while workshop threads run
|
||||
// The threads will check 'keep_running' which is modified by the signal handler
|
||||
while (keep_running) {
|
||||
sleep(1); // Check periodically
|
||||
}
|
||||
|
||||
// 6. Wait for all workshop threads to complete
|
||||
printf("Waiting for workshop threads to exit...\n");
|
||||
for (int i = 0; i < NUM_WORKSHOPS; ++i) {
|
||||
if (pthread_join(workshop_threads[i], NULL) != 0) {
|
||||
perror("pthread_join");
|
||||
}
|
||||
}
|
||||
printf("All workshop threads have exited.\n");
|
||||
|
||||
// 7. Cleanup: Unmap, close, and unlink shared memory and semaphore
|
||||
// This will be called by the signal handler or at the end of normal execution
|
||||
cleanup_ipc();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#define NUM_THREADS 5
|
||||
|
||||
// Semaphores to control output order
|
||||
sem_t semaphores[NUM_THREADS];
|
||||
|
||||
// Thread function
|
||||
void* thread_function(void* arg) {
|
||||
int thread_num = *(int*)arg;
|
||||
int thread_creation_number = thread_num + 1;
|
||||
|
||||
// Random delay between 1-5 seconds
|
||||
int delay = rand() % 5 + 1;
|
||||
printf("Thread %d created, will delay for %d seconds\n", thread_creation_number, delay);
|
||||
sleep(delay);
|
||||
|
||||
// Wait for signal to ensure proper output order
|
||||
sem_wait(&semaphores[thread_num]);
|
||||
|
||||
// Output thread information
|
||||
printf("Thread ID: %lu, Creation Number: %d\n", pthread_self(), thread_creation_number);
|
||||
|
||||
// Signal the next thread in reverse order
|
||||
if (thread_num > 0) {
|
||||
sem_post(&semaphores[thread_num - 1]);
|
||||
}
|
||||
|
||||
free(arg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main() {
|
||||
pthread_t threads[NUM_THREADS];
|
||||
int i;
|
||||
|
||||
// Seed the random number generator
|
||||
srand(time(NULL));
|
||||
|
||||
// Initialize all semaphores
|
||||
for (i = 0; i < NUM_THREADS; i++) {
|
||||
sem_init(&semaphores[i], 0, 0);
|
||||
}
|
||||
|
||||
// Create all threads
|
||||
printf("Creating threads...\n");
|
||||
for (i = 0; i < NUM_THREADS; i++) {
|
||||
int* thread_num = malloc(sizeof(int));
|
||||
*thread_num = i;
|
||||
pthread_create(&threads[i], NULL, thread_function, thread_num);
|
||||
usleep(100000); // Small delay between thread creation for clarity
|
||||
}
|
||||
|
||||
// Signal the last created thread to start the reverse order output
|
||||
sem_post(&semaphores[NUM_THREADS - 1]);
|
||||
|
||||
// Wait for all threads to complete
|
||||
for (i = 0; i < NUM_THREADS; i++) {
|
||||
pthread_join(threads[i], NULL);
|
||||
}
|
||||
|
||||
// Clean up semaphores
|
||||
for (i = 0; i < NUM_THREADS; i++) {
|
||||
sem_destroy(&semaphores[i]);
|
||||
}
|
||||
|
||||
printf("All threads completed execution.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user