What the code is doing: (FULL CODE is available at the bottom)
Parent(Producer) process reads files in an array one by one, and 3 bytes by 3 bytes and put it into shared_buffer(3 bytes of memory size)
using fread()
,
Child(Consumer) process reads from the shared_buffer
.
Mutual exclusion between read and write is ensured by synchronization with 3 mutexes: _full_
, _empty_
and _mutex_
.
However, even though It is ensured that parent and child access shared memory located in the same address, the data they received are different.
the first text file in the array:
This is a test file of 8 words.
my code: (extracted)
main:
#include <stdio.h>
//a lot of other libraries
#include "wordCount.h" //wordCount function
#define BUFFER_SIZE 3
char **file_paths;
int file_count = 0, word_count = 0;
int main(int argc, char **argv)
{
int process_id;
file_paths = malloc(100 * sizeof(char *)); //supposed that we already have files inside
int shmid, f,e,m;
char *shared_buffer;
shmid = shmget(IPC_PRIVATE, BUFFER_SIZE, 0666 | IPC_CREAT);
shared_buffer = (char *)shmat(shmid, 0, 0);
sem_t *_full_, *_empty_, *_mutex_;
f = shmget(IPC_PRIVATE, sizeof(sem_t), 0666 | IPC_CREAT);
e = shmget(IPC_PRIVATE, sizeof(sem_t), 0666 | IPC_CREAT);
m = shmget(IPC_PRIVATE, sizeof(sem_t), 0666 | IPC_CREAT);
_full_ = (sem_t *)shmat(f, 0, 0);
_empty_ = (sem_t *)shmat(e, 0, 0);
_mutex_ = (sem_t *)shmat(m, 0, 0);
sem_init(_full_, 1, 0);
sem_init(_empty_, 1, 1);
sem_init(_mutex_, 1, 1);
int *read_file_count;
int rKey = shmget(IPC_PRIVATE, sizeof(int), 0666 | IPC_CREAT);
read_file_count = (int *)shmat(rKey, 0, 0);
*read_file_count = 0;
switch (process_id = fork())
{
Parent:
default:
printf("Parent process: My ID is %jd\n", (intmax_t)getpid());
printf("address of the shared buffer in parent: %p\n", (void *)shared_buffer);
printf("parent: address of full: %p; empty: %p; mutex: %p\n", (void *)_full_, (void *)_empty_, (void *)_mutex_);
int value; sem_getvalue(_full_, &value);
printf("Value of _full_ semaphore: %d\n", value);
sem_getvalue(_empty_, &value);
printf("Value of _empty_ semaphore: %d\n", value);
sem_getvalue(_mutex_, &value);
printf("Value of _mutex_ semaphore: %d\n", value);
while(*read_file_count < file_count){ //LOOPING all the files in the array
FILE *fp = fopen(file_paths[*read_file_count],"r");
if( fp == NULL ){
printf("Fail to open file!\n");
exit(0);
}
size_t total_read = 0;
size_t num_read = 0;
printf("++++++++++Reading FILE %d++++++++++\n", *read_file_count);
while((num_read = fread(shared_buffer, sizeof(char), BUFFER_SIZE, fp)) > 0) { //LOOPing the same file
sem_wait(_empty_); printf("Parent process got empty. ");
sem_wait(_mutex_); printf("Parent process got mutex.\n");
for (size_t i = 0; i < num_read; i++) {
printf("address of shared_buffer[%zu]: %p, ", i, (void *)(shared_buffer+i));
printf("shared_buffer[%zu] = [%c]\n", i, shared_buffer[i]);
}
printf("------------------------------\n");
sem_post(_mutex_); printf("Parent process released mutex. ");
sem_post(_full_); printf("Parent process released full.\n");
}
(*read_file_count)++;
}
printf("Parent process: Finished.\n");
printf("Parent process: The total number of words is %d.\n", word_count);
saveResult("p2_result.txt", word_count);
break;
Child:
case 0: //child process
printf("Child process: My ID is %jd\n", (intmax_t)getpid());
printf("address of the shared buffer in child: %p\n", (void *)shared_buffer);
printf("child: address of full: %p; empty: %p; mutex: %p\n", (void *)_full_, (void *)_empty_, (void *)_mutex_);
sem_getvalue(_full_, &value); printf("Value of _full_ semaphore: %d\n", value);
sem_getvalue(_empty_, &value); printf("Value of _empty_ semaphore: %d\n", value);
sem_getvalue(_mutex_, &value); printf("Value of _mutex_ semaphore: %d\n", value);
while(*read_file_count < file_count){
sem_wait(_full_); printf("Child process got full. ");
sem_wait(_mutex_); printf("Child process got mutex.\n");
printf("Child:\n");
for (size_t i = 0; i < 3; i++) {
printf("address of shared_buffer[%zu]: %p, ", i, (void *)(shared_buffer+i));
printf("shared_buffer[%zu] = [%c]\n", i, shared_buffer[i]);
}
printf("previous word count: %d\n", word_count);
word_count += wordCount(shared_buffer);
printf("child counted words : %d\n", word_count);
printf("------------------------------\n");
sem_post(_mutex_); printf("Child process released mutex. ");
sem_post(_empty_); printf("Child process released empty.\n");
}
printf("Child process: Finished.\n");
exit(0);
OUTPUT:
address of the shared buffer in parent: 0x7fc37dd11000
Child process: My ID is 3231821
parent: address of full: 0x7fc37dcd4000; empty: 0x7fc37dcd3000; mutex: 0x7fc37dcd2000
address of the shared buffer in child: 0x7fc37dd11000
child: address of full: 0x7fc37dcd4000; empty: 0x7fc37dcd3000; mutex: 0x7fc37dcd2000
Value of _full_ semaphore: 0
Value of _full_ semaphore: 0
Value of _empty_ semaphore: 1
Value of _empty_ semaphore: 1
Value of _mutex_ semaphore: 1
Value of _mutex_ semaphore: 1
++++++++++Reading FILE 0++++++++++
Parent process got empty. Parent process got mutex.
address of shared_buffer[0]: 0x7fc37dd11000, shared_buffer[0] = [T]
address of shared_buffer[1]: 0x7fc37dd11001, shared_buffer[1] = [h]
address of shared_buffer[2]: 0x7fc37dd11002, shared_buffer[2] = [i]
------------------------------
Parent process released mutex. Parent process released full.
Child process got full. Child process got mutex.
Child:
address of shared_buffer[0]: 0x7fc37dd11000, shared_buffer[0] = [s]
address of shared_buffer[1]: 0x7fc37dd11001, shared_buffer[1] = [ ]
address of shared_buffer[2]: 0x7fc37dd11002, shared_buffer[2] = [i]
previous word count: 0
address of text[0]: 0x7fc37dd11000, text[0] = [s]
address of text[1]: 0x7fc37dd11001, text[1] = [ ]
address of text[2]: 0x7fc37dd11002, text[2] = [i]
child counted words : 2
------------------------------
Child process released mutex. Child process released empty.
Parent process got empty. Parent process got mutex.
address of shared_buffer[0]: 0x7fc37dd11000, shared_buffer[0] = [s]
address of shared_buffer[1]: 0x7fc37dd11001, shared_buffer[1] = [ ]
address of shared_buffer[2]: 0x7fc37dd11002, shared_buffer[2] = [i]
------------------------------
Parent process released mutex. Parent process released full.
Child process got full. Child process got mutex.
Child:
address of shared_buffer[0]: 0x7fc37dd11000, shared_buffer[0] = [s]
address of shared_buffer[1]: 0x7fc37dd11001, shared_buffer[1] = [ ]
address of shared_buffer[2]: 0x7fc37dd11002, shared_buffer[2] = [a]
previous word count: 2
address of text[0]: 0x7fc37dd11000, text[0] = [s]
address of text[1]: 0x7fc37dd11001, text[1] = [ ]
address of text[2]: 0x7fc37dd11002, text[2] = [a]
child counted words : 4
------------------------------
Child process released mutex. Child process released empty.
Parent process got empty. Parent process got mutex.
address of shared_buffer[0]: 0x7fc37dd11000, shared_buffer[0] = [s]
address of shared_buffer[1]: 0x7fc37dd11001, shared_buffer[1] = [ ]
address of shared_buffer[2]: 0x7fc37dd11002, shared_buffer[2] = [a]
------------------------------
Parent process released mutex. Parent process released full.
Child process got full. Child process got mutex.
Child:
address of shared_buffer[0]: 0x7fc37dd11000, shared_buffer[0] = [ ]
address of shared_buffer[1]: 0x7fc37dd11001, shared_buffer[1] = [t]
address of shared_buffer[2]: 0x7fc37dd11002, shared_buffer[2] = [e]
previous word count: 4
address of text[0]: 0x7fc37dd11000, text[0] = [ ]
address of text[1]: 0x7fc37dd11001, text[1] = [t]
address of text[2]: 0x7fc37dd11002, text[2] = [e]
child counted words : 6
------------------------------
Child process released mutex. Child process released empty.
Parent process got empty. Parent process got mutex.
address of shared_buffer[0]: 0x7fc37dd11000, shared_buffer[0] = [ ]
address of shared_buffer[1]: 0x7fc37dd11001, shared_buffer[1] = [t]
address of shared_buffer[2]: 0x7fc37dd11002, shared_buffer[2] = [e]
------------------------------
Parent process released mutex. Parent process released full.
Child process got full. Child process got mutex.
Child:
address of shared_buffer[0]: 0x7fc37dd11000, shared_buffer[0] = [s]
address of shared_buffer[1]: 0x7fc37dd11001, shared_buffer[1] = [t]
address of shared_buffer[2]: 0x7fc37dd11002, shared_buffer[2] = [ ]
previous word count: 6
address of text[0]: 0x7fc37dd11000, text[0] = [s]
address of text[1]: 0x7fc37dd11001, text[1] = [t]
address of text[2]: 0x7fc37dd11002, text[2] = [ ]
child counted words : 8
------------------------------
Child process released mutex. Child process released empty.
Parent process got empty. Parent process got mutex.
address of shared_buffer[0]: 0x7fc37dd11000, shared_buffer[0] = [s]
address of shared_buffer[1]: 0x7fc37dd11001, shared_buffer[1] = [t]
address of shared_buffer[2]: 0x7fc37dd11002, shared_buffer[2] = [ ]
------------------------------
Parent process released mutex. Parent process released full.
Child process got full. Child process got mutex.
Child:
address of shared_buffer[0]: 0x7fc37dd11000, shared_buffer[0] = [f]
address of shared_buffer[1]: 0x7fc37dd11001, shared_buffer[1] = [i]
address of shared_buffer[2]: 0x7fc37dd11002, shared_buffer[2] = [l]
previous word count: 8
address of text[0]: 0x7fc37dd11000, text[0] = [f]
address of text[1]: 0x7fc37dd11001, text[1] = [i]
address of text[2]: 0x7fc37dd11002, text[2] = [l]
child counted words : 9
------------------------------
Child process released mutex. Child process released empty.
Parent process got empty. Parent process got mutex.
address of shared_buffer[0]: 0x7fc37dd11000, shared_buffer[0] = [f]
address of shared_buffer[1]: 0x7fc37dd11001, shared_buffer[1] = [i]
address of shared_buffer[2]: 0x7fc37dd11002, shared_buffer[2] = [l]
------------------------------
Parent process released mutex. Parent process released full.
Child process got full. Child process got mutex.
Child:
address of shared_buffer[0]: 0x7fc37dd11000, shared_buffer[0] = [e]
address of shared_buffer[1]: 0x7fc37dd11001, shared_buffer[1] = [ ]
address of shared_buffer[2]: 0x7fc37dd11002, shared_buffer[2] = [o]
previous word count: 9
address of text[0]: 0x7fc37dd11000, text[0] = [e]
address of text[1]: 0x7fc37dd11001, text[1] = [ ]
address of text[2]: 0x7fc37dd11002, text[2] = [o]
child counted words : 11
------------------------------
Child process released mutex. Child process released empty.
Parent process got empty. Parent process got mutex.
address of shared_buffer[0]: 0x7fc37dd11000, shared_buffer[0] = [e]
address of shared_buffer[1]: 0x7fc37dd11001, shared_buffer[1] = [ ]
address of shared_buffer[2]: 0x7fc37dd11002, shared_buffer[2] = [o]
------------------------------
Parent process released mutex. Parent process released full.
Child process got full. Child process got mutex.
Child:
address of shared_buffer[0]: 0x7fc37dd11000, shared_buffer[0] = [f]
address of shared_buffer[1]: 0x7fc37dd11001, shared_buffer[1] = [ ]
address of shared_buffer[2]: 0x7fc37dd11002, shared_buffer[2] = [8]
previous word count: 11
address of text[0]: 0x7fc37dd11000, text[0] = [f]
address of text[1]: 0x7fc37dd11001, text[1] = [ ]
address of text[2]: 0x7fc37dd11002, text[2] = [8]
...
As you can see from the output:
Parent process got empty. Parent process got mutex.
address of shared_buffer[0]: 0x7fc37dd11000, shared_buffer[0] = [T]
address of shared_buffer[1]: 0x7fc37dd11001, shared_buffer[1] = [h]
address of shared_buffer[2]: 0x7fc37dd11002, shared_buffer[2] = [i]
------------------------------
Parent process released mutex. Parent process released full.
Child process got full. Child process got mutex.
Child:
address of shared_buffer[0]: 0x7fc37dd11000, shared_buffer[0] = [s]
address of shared_buffer[1]: 0x7fc37dd11001, shared_buffer[1] = [ ]
address of shared_buffer[2]: 0x7fc37dd11002, shared_buffer[2] = [i]
They literally access the same memory, why is the output different, and as I can observe, what the child read are actually the next 3 characters following with the 3 characters read by parents, why would this happen? How to fix it?
Don't mind the word Count function and the text[]
that is printed out. The main issue here is why child reads different buffer data from parent.
FULL CODE:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <pthread.h>
#include <sys/shm.h>
#include <errno.h>
#include <assert.h>
#include <dirent.h>
#include "helpers.h"
#define BUFFER_SIZE 3
/**
* @brief This function recursively traverse the source directory.
*
* @param dir_name : The source directory name.
*/
char **file_paths;
int file_count = 0;
int word_count = 0;
void traverseDir(char *dir_name);
int main(int argc, char **argv)
{
int process_id;
file_paths = malloc(100 * sizeof(char *));
char *dir_name = argv[1];
if (argc < 2){
printf("Main process: Please enter a source directory name.\nUsage: ./main <dir_name>\n");
exit(-1);
}
traverseDir(dir_name);
if (file_count == 0)
{
printf("Main process: No txt files found in the source directory.\n");
exit(-1);
}
if (file_count > 100)
{
printf("Main process: The number of txt files is greater than 100.\n");
exit(-1);
}
printf("Found %d files in the source directory.\n", file_count);
for (int i = 0; i < file_count; i++)
{
printf("%s\n", file_paths[i]);
}
int shmid;
int f,e,m;
char *shared_buffer;
shmid = shmget(IPC_PRIVATE, BUFFER_SIZE, 0666 | IPC_CREAT);
shared_buffer = (char *)shmat(shmid, 0, 0);
sem_t *_full_, *_empty_, *_mutex_;
f = shmget(IPC_PRIVATE, sizeof(sem_t), 0666 | IPC_CREAT);
e = shmget(IPC_PRIVATE, sizeof(sem_t), 0666 | IPC_CREAT);
m = shmget(IPC_PRIVATE, sizeof(sem_t), 0666 | IPC_CREAT);
_full_ = (sem_t *)shmat(f, 0, 0);
_empty_ = (sem_t *)shmat(e, 0, 0);
_mutex_ = (sem_t *)shmat(m, 0, 0);
sem_init(_full_, 1, 0);
sem_init(_empty_, 1, 1);
sem_init(_mutex_, 1, 1);
int *read_file_count;
int rKey = shmget(IPC_PRIVATE, sizeof(int), 0666 | IPC_CREAT);
read_file_count = (int *)shmat(rKey, 0, 0);
*read_file_count = 0;
switch (process_id = fork())
{
default:
printf("Parent process: My ID is %jd\n", (intmax_t)getpid());
printf("address of the shared buffer in parent: %p\n", (void *)shared_buffer);
printf("parent: address of full: %p; empty: %p; mutex: %p\n", (void *)_full_, (void *)_empty_, (void *)_mutex_);
int value;
sem_getvalue(_full_, &value);
printf("Value of _full_ semaphore: %d\n", value);
sem_getvalue(_empty_, &value);
printf("Value of _empty_ semaphore: %d\n", value);
sem_getvalue(_mutex_, &value);
printf("Value of _mutex_ semaphore: %d\n", value);
while(*read_file_count < file_count){
FILE *fp = fopen(file_paths[*read_file_count],"r");
if( fp == NULL ){
printf("Fail to open file!\n");
exit(0);
}
size_t total_read = 0;
size_t num_read = 0;
printf("++++++++++Reading FILE %d++++++++++\n", *read_file_count);
while((num_read = fread(shared_buffer, sizeof(char), BUFFER_SIZE, fp)) > 0) {
sem_wait(_empty_); printf("Parent process got empty. ");
sem_wait(_mutex_); printf("Parent process got mutex.\n");
if(shared_buffer[0] == ' '){
word_count--;
} else if (shared_buffer[num_read] == ' '){
word_count--;
}
for (size_t i = 0; i < num_read; i++) {
printf("address of shared_buffer[%zu]: %p, ", i, (void *)(shared_buffer+i));
printf("shared_buffer[%zu] = [%c]\n", i, shared_buffer[i]);
}
printf("------------------------------\n");
sem_post(_mutex_); printf("Parent process released mutex. ");
sem_post(_full_); printf("Parent process released full.\n");
}
(*read_file_count)++;
}
printf("Parent process: Finished.\n");
printf("Parent process: The total number of words is %d.\n", word_count);
saveResult("p2_result.txt", word_count);
break;
case 0:
printf("Child process: My ID is %jd\n", (intmax_t)getpid());
printf("address of the shared buffer in child: %p\n", (void *)shared_buffer);
printf("child: address of full: %p; empty: %p; mutex: %p\n", (void *)_full_, (void *)_empty_, (void *)_mutex_);
sem_getvalue(_full_, &value);
printf("Value of _full_ semaphore: %d\n", value);
sem_getvalue(_empty_, &value);
printf("Value of _empty_ semaphore: %d\n", value);
sem_getvalue(_mutex_, &value);
printf("Value of _mutex_ semaphore: %d\n", value);
sleep(3);
while(*read_file_count < file_count){
sem_wait(_full_); printf("Child process got full. ");
sem_wait(_mutex_); printf("Child process got mutex.\n");
printf("Child:\n");
for (size_t i = 0; i < 3; i++) {
printf("address of shared_buffer[%zu]: %p, ", i, (void *)(shared_buffer+i));
printf("shared_buffer[%zu] = [%c]\n", i, shared_buffer[i]);
}
printf("previous word count: %d\n", word_count);
word_count += wordCount(shared_buffer);
printf("child counted words : %d\n", word_count);
printf("------------------------------\n");
sem_post(_mutex_); printf("Child process released mutex. ");
sem_post(_empty_); printf("Child process released empty.\n");
}
printf("Child process: Finished.\n");
exit(0);
case -1:
printf("Fork failed!\n");
exit(-1);
}
exit(0);
}
/**
* @brief This function recursively traverse the source directory.
*
* @param dir_name : The source directory name.
*/
void traverseDir(char *dir_name)
{
DIR *dir;
struct dirent *ent;
if ((dir = opendir(dir_name)) != NULL)
{
while ((ent = readdir(dir)) != NULL)
{
if (ent->d_type == DT_DIR)
{
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
{
continue;
}
char *new_dir_name = malloc(strlen(dir_name) + strlen(ent->d_name) + 2);
strcpy(new_dir_name, dir_name);
strcat(new_dir_name, "/");
strcat(new_dir_name, ent->d_name);
traverseDir(new_dir_name);
}
else
{
if (strstr(ent->d_name, ".txt") != NULL)
{
char *new_file_path = malloc(strlen(dir_name) + strlen(ent->d_name) + 2);
strcpy(new_file_path, dir_name);
strcat(new_file_path, "/");
strcat(new_file_path, ent->d_name);
file_paths[file_count] = new_file_path;
file_count++;
}
}
}
closedir(dir);
}
else
{
perror("");
return;
}
}
helper:
int wordCount(char *text) {
int counter = 0;
int i=0;
while(text[i] != '\0'){
printf("address of text[%d]: %p, ", i, &text[i]);
printf("text[%d] = [%c]\n", i, text[i]);
if (text[i] == ' ' || text[i] == '\n'){
counter++;
}
i++;
}
printf("\n");
return counter + 1;
}
helper.h only provides the wordCount function, can ignore