Reading File and enforcing order of operation between processes - c

I am attempting to follow a tutorial which asks me to edit example code to get a program to run two processes which take turns to output the lyrics to a song ('There's a hole in the bucket').
My problem is that the file gets outputted as a whole and not alternativley like it should see screen shot for what i am talking about : http://imgur.com/NusvhVA
My code is below. Thanks.
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
#define KEY 87654 //Unique semaphore key
int main()
{
int id; /* Number by which the semaphore is known within a program */
FILE *file;
file = fopen("207song.txt", "r" );
int c;
union semun {
int val;
struct semid_ds *buf;
ushort * array;
} argument;
argument.val = 1;
/* Create the semaphore with external key KEY if it doesn't already
exists. Give permissions to the world. */
id = semget(KEY, 1, 0666 | IPC_CREAT);
/* Always check system returns. */
if(id < 0) {
fprintf(stderr, "Unable to obtain semaphore.\n");
exit(0);
}
/* What we actually get is an array of semaphores. The second
argument to semget() was the array dimension - in our case
1. */
/* Set the value of the number 0 semaphore in semaphore array
# id to the value 0. */
if( semctl(id, 0, SETVAL, argument) < 0) {
fprintf( stderr, "Cannot set semaphore value.\n");
} else {
fprintf(stderr, "Semaphore %d initialized.\n", KEY);
}
int pid=fork();
const int HENRY_DONE = 0;
const int LIZA_DONE = 1;
volatile int flag = HENRY_DONE;
if(pid) {
struct sembuf operations[1];
int retval; /* Return value from semop() */
/* Get the index for the semaphore with external name KEY. */
id = semget(KEY, 1, 0666);
if(id < 0){
/* Semaphore does not exist. */
fprintf(stderr, "Program sema cannot find semaphore, exiting.\n");
exit(0);
}
operations[0].sem_num = 0;
/* Which operation? Subtract 1 from semaphore value : */
operations[0].sem_op = -1;
/* Set the flag so we will wait : */
operations[0].sem_flg = 0;
while(1){
//Process 1
//wait
operations[0].sem_op = -1;
retval = semop(id, operations, 1);
//critical section
printf("Liza's Part: \n");
fflush(stdout);
sleep(1);
while ((c = getc(file)) !=EOF)
if (c == "\n") {
putchar(c);
break;
}
else
putchar(c);
fflush(stdout);
operations[0].sem_op = 1;
//signal
retval = semop(id, operations, 1);
}
}else{
//Process 2
struct sembuf operations[1];
int retval; /* Return value from semop() */
/* Get the index for the semaphore with external name KEY. */
id = semget(KEY, 1, 0666);
if(id < 0){
/* Semaphore does not exist. */
fprintf(stderr, "Program sema cannot find semaphore, exiting.\n");
exit(0);
}
operations[0].sem_num = 0;
/* Which operation? Subtract 1 from semaphore value : */
operations[0].sem_op = -1;
/* Set the flag so we will wait : */
operations[0].sem_flg = 0;
while(1){
//wait
operations[0].sem_op = -1;
retval = semop(id, operations, 1);
//critical section
printf("Henry's Part: \n");
fflush(stdout);
sleep(1);
while ((c = getc(file)) !=EOF)
if (c == "\n") {
putchar(c);
break;
}
else
putchar(c);
fflush(stdout);
//signal
operations[0].sem_op = 1;
retval = semop(id, operations, 1);
}
}
}

If your while loop you have:
while ((c = getc(file)) !=EOF)
if (c == "\n") {
getc returns an integer, "\n" is a c-string of type char*. That
comparison will not match, leading the first comsumer to show the whole file.
You probably want
c == '\n'
note the single quotes 'rather than double " The single quote will be a char, which will compare reasonably with an int.

Related

How do I print stored data from the shared memory?

I have the following program:
#include <stdio.h>
#include <sys/types.h>
#define MAX_COUNT 100
void ChildProcess(void);
void ParentProcess(void);
void main(void)
{
pid_t pid;
pid = fork();
if (pid == 0)
ChildProcess();
else
ParentProcess();
}
void ChildProcess(void)
{
int i;
for (i = 1; i <= MAX_COUNT; i++)
printf(" This line is from child, value = %d\n", i);
printf(" *** Child process is done ***\n");
}
void ParentProcess(void)
{
int i;
for (i = 1; i <= MAX_COUNT; i++)
printf("This line is from parent, value = %d\n", i);
printf("*** Parent is done ***\n");
}
I have to modify it in a way that both the parent and the child print stored data from the shared memory in the following way:
Create and initialize the shared memory in the parent.
Fill the shared memory with 5 integer numbers. (I should allocate enough shared memory to store the 5 ints.)
Fork from the parent to the child.
If fork is successful, then the child process must print the values stored in the shared memory as shown in the expected output where N1, N2, N3, N4, N5 are the numbers found in the shared memory.
Expected output
What I did in the ParentProcess function is the following:
void ParentProcess(void)
{
int i;
for (i = 1; i <= MAX_COUNT; i++)
printf("This line is from parent, value = %d\n", i);
printf("*** Parent is done ***\n");
int localVar = 0;
int* p = (int*) malloc(2);
pid_t childPID = fork();
*p = 0;
if (childPID >= 0)
{
printf("\nChild process has started\n");
if (childPID == 0)
{
localVar++;
globalVar++;
printf("Child process has found the following data %d,", *p);
*p = 70;
printf( " %d,", *p);
*p = 66;
printf(" %d,", *p);
*p = 51;
printf(" %d,", *p);
*p = 90;
printf(" %d in shared memory\n",*p);
printf("Child is existing\n\n");
}
}
}
And now I realize that I did it completely wrong but I have no idea how to fix that. I suppose I have to use shmget to create the shared memory, but then what? How do I store values in it?
If you find that you cannot help me with this or it is too long, please share sources where I can learn more about C programming in Linux, particularly regarding the usage of shared memory. Thank you in advance
It may be better to make it clear what you want to do first because as far as I read your code you call fork() twice in your code (once in main() function and once in ParentProcess() function)
So I write general solution for parent/child shared memory. There are several ways to achieve shared memory but this is one example which is modified version of the code here
How to use shared memory with Linux in C
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/wait.h>
void *create_shared_memory(size_t size)
{
int protection = PROT_READ | PROT_WRITE;
int visibility = MAP_SHARED | MAP_ANONYMOUS;
return mmap(NULL, size, protection, visibility, -1, 0);
}
int main()
{
// Allocate 4 ints
void *shmem = create_shared_memory(sizeof(int)*4);
if( shmem == NULL ){
fprintf(stderr, "Failed to create shared memory\n");
return -1;
}
// Initialize 4 ints
((int*)shmem)[0] = 10;
((int*)shmem)[1] = 100;
((int*)shmem)[2] = 1000;
((int*)shmem)[3] = 10000;
int pid = fork();
if (pid == 0)
{
// Print 4 ints in child
printf("Child reading int 0: %d\n", ((int*)shmem)[0]);
printf("Child reading int 1: %d\n", ((int*)shmem)[1]);
printf("Child reading int 2: %d\n", ((int*)shmem)[2]);
printf("Child reading int 3: %d\n", ((int*)shmem)[3]);
printf("Child end\n");
}
else
{
printf("Parent waiting for child ends...\n");
waitpid(pid, NULL, 0);
printf("Parent ends\n");
}
int ret = munmap(shmem, sizeof(int)*4);
if( ret != 0 ){
fprintf(stderr, "Failed to unmap shared memory\n");
return -1;
}
return 0;
}
I've written a small piece of c code which you might find helpful:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#define NUM_INTS 5
int main(int argc, char *argv[])
{
key_t key = (key_t) 123456;
int shmgetrc, semgetrc;
struct shmid_ds ds;
int *shared_values;
int i;
struct sembuf sops[2];
int semid;
sops[0].sem_num = 0; /* Operate on semaphore 0 */
sops[0].sem_op = 0; /* Wait for value to equal 0 */
sops[0].sem_flg = 0;
sops[1].sem_num = 0; /* Operate on semaphore 0 */
sops[1].sem_op = 1; /* Increment value by one */
sops[1].sem_flg = 0;
/* create SHM segment */
shmgetrc = shmget(key, NUM_INTS * sizeof(int), IPC_CREAT | IPC_EXCL | 0x180);
if (shmgetrc < 0) {
perror("shmget failed...");
exit(1);
}
/* retrieve the address of the segment */
shared_values = (int *) shmat(shmgetrc, NULL, 0);
/* create a semaphore */
semgetrc = semget(key, 1, IPC_CREAT | IPC_EXCL | 0x180);
if (semgetrc < 0) {
perror("semget failed...");
exit(1);
}
/* lock the semaphore */
if (semop(semgetrc, sops, 2) == -1) {
perror("semop lock failed ...");
exit(1);
}
/* fill it with values */
for (i = 0; i < NUM_INTS; ++i) {
shared_values[i] = i;
}
/* unlock the semaphore */
sops[0].sem_op = -1;
if (semop(semgetrc, sops, 1) == -1) {
perror("semop release failed ...");
exit(1);
}
/* here something else could happen */
sleep(60);
/* lock the semaphore */
sops[0].sem_op = 0;
if (semop(semgetrc, sops, 2) == -1) {
perror("semop lock failed ...");
exit(1);
}
/* print values */
for (i = 0; i < NUM_INTS; ++i) {
printf("%d ", shared_values[i]);
}
printf("\n");
/* unlock the semaphore */
sops[0].sem_op = -1;
if (semop(semgetrc, sops, 1) == -1) {
perror("semop release failed ...");
exit(1);
}
/* remove the semaphore */
if (semctl(semgetrc, semgetrc, IPC_RMID) < 0) {
perror("semctl failed ...");
exit(1);
}
/* remove shm segment again */
if (shmctl(shmgetrc, IPC_RMID, &ds) < 0) {
perror("shmctl failed ...");
exit(1);
}
exit(0);
}
It was not my intention to write the most beautiful code ever written, just an example that shows:
how to create a shm segment
how to retrieve the address and to use it
how to remove it
Additionally, I've used a semaphore to protect the access.
Contrary to the other answer, I've used the ipc interface, not mmap().

fcntl F_GETLK always returns F_UNLCK

I am trying to understand POSIX file-region locks in C. The program below is really simple, sets the lock to F_WRLCK and then gets locks. There is no errors during opening/setting lock. Unfortunatelly it's always returning F_UNLCK. Where is the mistake ? Is it possible that it doesnt work on OSX correctly ?
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
void printLockType(int lock) {
if ( lock == F_RDLCK ) {
printf("readlock %i \n", lock);
}else if ( lock == F_WRLCK ) {
printf("writelock %i \n", lock);
}else if ( lock == F_UNLCK ) {
printf("unlock %i \n", lock);
} else {
printf("other %i\n", lock);
}
}
int main(int argc, char *argv[])
{
int fd;
struct flock fl ,fl2;
fl2.l_type = F_RDLCK; /* read/write lock */
fl2.l_whence = 0; /* beginning of file */
fl2.l_start = 0; /* offset from l_whence */
fl2.l_len = 100; /* length, 0 = to EOF */
fl2.l_pid = getpid();
fl.l_type = F_WRLCK; /* read/write lock */
fl.l_whence = 0; /* beginning of file */
fl.l_start = 0; /* offset from l_whence */
fl.l_len = 1000; /* length, 0 = to EOF */
fl.l_pid = getpid();
if ((fd = open("xxx", O_RDWR)) == -1) {
perror("open");
exit(1);
}
if (fcntl(fd, F_SETLK, &fl) == -1) {
perror("fcntl");
exit(1);
}
if(fcntl(fd, F_GETLK, &fl2) == -1) {
printf("%s \n", strerror(errno));
} else {
printLockType(fl2.l_type);
}
return 0;
}
You're misunderstanding the F_GETLK query. It returns F_UNLCK when nothing blocks the calling process from placing a lock of the given type at the given position.
Since the calling process is the one that created these existing locks, it can also create this new lock.
The Mac OS X manuals say
F_GETLK
Get the first lock that blocks the lock description pointed to by the third argument, arg,
taken as a pointer to a struct flock (see above). The information retrieved overwrites the
information passed to fcntl in the flock structure. If no lock is found that would prevent
this lock from being created, the structure is left unchanged by this function call except
for the lock type which is set to F_UNLCK.

Running concurrent processes using pipe in C

I'm working on an assignment in C aimed at using a pipe to pass variables between two processes. Both processes must be forked from the parent, and they must run concurrently to pass one character at a time (sort of demonstrated below).
The issue I'm having is that the fork()ed processes are not running concurrently. The sender seems to go first, and after running for ~26 seconds the receiver begins. Here is the code I have written:
#include <stdio.h>
int ret;
int pipearray[2];
char buffer[26];
void mysender();
void myreceiver();
int main()
{
int pid = 0;
int i = 0;
ret = pipe(pipearray);
while (i < 2) {
pid = fork();
if ( pid == 0 && i == 0 ) /* child process execution (receiver) */
{
myreceiver();
printf("Your receiver is done\n");
exit(0);
}
else if ( pid == 0 && i == 1 ) /* now executes sender */
{
mysender();
printf("Your sender is done\n");
exit(0);
}
++i;
}
close(pipearray[0]);
close(pipearray[1]);
sleep(30);
printf("Parent function has finished.\n");
return 0;
}
void mysender()
{
char c;
int index = 90;
close(pipearray[0]);
while (index > 64) /* loop for all values of A-Z in ASCII */
{
c = (char) index;
open(pipearray[1]);
write(pipearray[1], c, sizeof(c)); /* Sends letter to pipe */
--index;
sleep(1);
}
close(pipearray[1]);
}
void myreceiver()
{
int index = 0;
close(pipearray[1]);
while(buffer != 'A') /*loop runs until 'A' is handled */
{
sleep(1);
open(pipearray[0]);
read(pipearray[0], buffer, 1);
printf("%s", &buffer);
index++;
if ( index == 26 ) { break; }
}
close(pipearray[0]);
}
Expected Result:
ZYXWVUTSRQPONMLKJIHGFEDCBA
Your sender is done
Your receiver is done
The parent function has finished.
My result:
Your sender is done
The parent function has finished.
Your receiver is done
I'm very new to C programming but I've been banging away at this for a while. Any tips to why these might not be running simultaneously would be very appreciated.
There is many errors in your code. Don't try to open the pipe after fork, it is already open and has no name. Write should use the address of c. Read must read into the right place. A flush must be done after write to stdout. Your conditional must be slightly modified to be guaranteed correct. The parent process must wait its children. Here is the modified code :
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
int ret;
int pipearray[2];
char buffer[26];
void mysender();
void myreceiver();
int main()
{
int pid = 0;
int i = 0;
ret = pipe(pipearray);
while (i < 2) {
pid = fork();
if ( pid == 0 && i == 0 ) /* child process execution (receiver) */
{
myreceiver();
printf("Your receiver is done\n");
exit(0);
}
else if ( pid == 0 && i == 1 ) /* now executes sender */
{
mysender();
printf("Your sender is done\n");
exit(0);
}
++i;
}
close(pipearray[0]);
close(pipearray[1]);
// Don't sleep, but wait until the end of the two children
wait(NULL);
wait(NULL);
// sleep(30);
printf("Parent function has finished.\n");
return 0;
}
void mysender()
{
char c;
int index = 90;
close(pipearray[0]);
while (index > 64) /* loop for all values of A-Z in ASCII */
{
c = (char) index;
// try to open a anonymous pipe is a non-sense
// open(pipearray[1]);
// Send a buffer by its address
write(pipearray[1], &c, sizeof(c)); /* Sends letter to pipe */
--index;
sleep(1);
}
close(pipearray[1]);
}
void myreceiver()
{
int index = 0;
close(pipearray[1]);
// Ensure condition is entered first
buffer[index] = 0;
// This is not the best condition ever, but ok.
while(buffer[index] != 'A') /*loop runs until 'A' is handled */
{
sleep(1);
// Don't open an anonymous pipe
// open(pipearray[0]);
// Read at the right position
read(pipearray[0], buffer+index, 1);
// print and flush, could also be printf("%s"...); flush(stdout);
printf("%s\n", buffer);
index++;
if ( index == 26 ) { break; }
}
close(pipearray[0]);
}
Now, consider to remove the sleeps in the reader, as it will be synchronized with the writes such that no read is possible if no write has been done. Alos consider to read more that one byte, because there is no concept of message, so that you can read as much byte you consider necessary to read, and as usual it is better to try reading a bunch of bytes when you can.

IO in C standard and C POSIX

I have problem when testing difference IO function between C standard and C POSIX.
I wrote two program that read a file character by character passed as a parameter, and display each character as soon as it is read. These programs will consist of three processes that share the same descriptor and act identically (the identity of each process is shown with the character read).
The first program will be written with the POSIX standard functions (open, read)
int main(int argc, char **argv){
int fd; /* Descriptor */
char *fic = argv[1]; /* Le nom du fichier */
int end = 0;
/* Sémaphore */
struct sembuf operation;
int sem_id;
sem_id = semget(ftok(fic, 'S'), 1, 0666|IPC_CREAT);
semctl(sem_id, 0, SETVAL, 1);
if((fd = open(fic, O_RDONLY, 0666))==-1){
perror("open file\n");
}
int i = 0;
char c;
for(i=0; i<3; i++){
if(fork()==0){
/* Lire */
while(end==0){
operation.sem_num = 0;
operation.sem_op = -1;
semop(sem_id, &operation, 1);
if(read(fd, &c, sizeof(char))>0){
printf("[Pid=%d]%c\n", getpid(), c);
}
else{
end = 1;
break;
}
operation.sem_num = 0;
operation.sem_op = 1;
semop(sem_id, &operation, 1);
sleep(1);
}
return EXIT_SUCCESS;
}
else continue;
}
for(i=0; i<3; i++){
wait(NULL);
}
close(fd);
semctl(sem_id, 0, IPC_RMID, NULL);
return EXIT_SUCCESS;
}
The second program will be written with the C library functions (fopen, fgetc)
int main(int argc, char **argv){
FILE *fd; /* Descriptor */
char *fic = argv[1];
int end = 0;
/* Sémaphore */
struct sembuf operation;
int sem_id;
sem_id = semget(ftok(fic, 'S'), 1, 0666|IPC_CREAT);
semctl(sem_id, 0, SETVAL, 1);
if((fd = fopen(fic, "r"))==NULL){
perror("open file\n");
}
int i = 0;
char c;
for(i=0; i<3; i++){
if(fork()==0){
while(end==0){
operation.sem_num = 0;
operation.sem_op = -1;
semop(sem_id, &operation, 1);
if((c = fgetc(fd))!=EOF){
printf("[Pid=%d]%c\n", getpid(), c);
}
else{
end = 1;
break;
}
operation.sem_num = 0;
operation.sem_op = 1;
semop(sem_id, &operation, 1);
sleep(1);
}
return EXIT_SUCCESS;
}
else continue;
}
for(i=0; i<3; i++){
wait(NULL);
}
fclose(fd);
semctl(sem_id, 0, IPC_RMID, NULL);
return EXIT_SUCCESS;
}
In case of C POSIX, I found that 3 processes works in parallel using locking mechanism of semaphore.
But in case of C standard, there is only one process that read and display character in the screen.
Could anyone tell me the reason of this difference?
Thanks so much.
If I understand correctly, you run your programs and see output like this:
$ echo foo > /tmp/input
$ ./synchronized-read /tmp/input # PIDs differ; the readers "share" the input
[Pid=124] f
[Pid=123] o
[Pid=125] o
[Pid=123] # <-- (newline)
$ ./synchronized-fgetc /tmp/input # PIDs are all the same; one reader reads all
[Pid=567] f
[Pid=567] o
[Pid=567] o
[Pid=567] # <-- (newline)
The reason is that read operates directly on files, whereas fgetc operates on buffered standard IO streams.
So, in the first program, the readers each read a byte at a time off of the file directly. In the second program, the first reader to obtain the semaphore reads in the entire file — you didn't show us sample input but this fits your problem description — meaning the other readers immediately encounter EOF and exit.
If you modify the child logic in each to printf("[Pid=%d]EOF\n", getpid()) at end of input, you'll clearly see it.

Cat unix command multithread implementation

Hi im trying to implement faster cat than the one provided.
My current implementation looks like this:
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#define BUF_SIZE 1024*1024*1024
char buffer[BUF_SIZE];
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_var = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond_var2 = PTHREAD_COND_INITIALIZER;
int readed = 0;
/*
Read characters from standard input and saves them to buffer
*/
void *consumer(void *data) {
int r;
while(1) {
//---------CRITICAL CODE--------------
//------------REGION------------------
pthread_mutex_lock(&mutex);
if (readed > 0)
{
pthread_cond_wait(&cond_var2, &mutex);
}
r = read(0, buffer, BUF_SIZE);
readed = r;
pthread_cond_signal(&cond_var);
pthread_mutex_unlock(&mutex);
//------------------------------------
if (r == -1){
printf("Error reading\n");
}
else if (r == 0) {
pthread_exit(NULL);
}
}
}
/*
Print chars readed by consumer from standard input to standard output
*/
void *out_producer(void *data) {
int w;
while(1){
//---------CRITICAL CODE--------------
//-------------REGION-----------------
pthread_mutex_lock(&mutex);
if (readed == 0)
{
pthread_cond_wait(&cond_var, &mutex);
}
w = write(1, buffer, readed);
readed = 0;
pthread_cond_signal(&cond_var2);
pthread_mutex_unlock(&mutex);
//------------------------------------
if (w == -1){
printf("Error writing\n");
}
else if (w == 0) {
pthread_exit(NULL);
}
}
}
What would you suggest to make it faster?
Any ideas?
I was thinking about the BUF_SIZE, what would you think would be optimal size of buffer?
Main just makes the threads:
int main() {
// Program RETURN value
int return_value = 0;
// in - INPUT thread
// out - OUTPUT thread
pthread_t in, out;
// Creating in thread - should read from standard input (0)
return_value = pthread_create(&in , NULL, consumer, NULL);
if (return_value != 0) {
printf("Error creating input thread exiting with code error: %d\n", return_value);
return return_value;
}
// Creating out thread - should write to standard output (1)
return_value = pthread_create(&out, NULL, out_producer, NULL);
if (return_value != 0) {
printf("Error creating output thread exiting with code error: %d\n", return_value);
return return_value;
}
return_value = pthread_join(in, NULL);
return_value = pthread_join(out, NULL);
return return_value;
}
How exactly is adding threads to cat going to make it faster? You can't just throw parallelism at any program and expect it to run faster.
Cat basically just transports every line of input (usually from a file) to output. Since it's important that the lines are in order, you have to use mutual exclusion to avoid racing.
The upper bound of the speed (the fastest that cat can run) in parallel cannot be higher than cat in serial, since every thread must perform the serial actions, along with the cost of synchronization.

Resources