IO in C standard and C POSIX - c

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.

Related

Problems using the fork function linux

I'm trying to achieve the following: I read nr words from input text file and for each word I want to start a child process to modify the word and return it in an output text file. The output fluctuates, sometimes I get the words messed up ( apple banana into appbananale) and sometimes the output file is 20kb and it freezes the text editor.
int main(int argc, char **argv){
int in, out, i, nr, k, j;
char buffer[100];
in = open(argv[1], O_RDONLY);
if (in == -1){
perror(NULL);
return errno;
}
out = open(argv[2], O_WRONLY | O_CREAT, 0666);
if (out == -1){
perror(NULL);
return errno;
}
if (read(in, buffer, 100) == -1){
perror(NULL);
return errno;
}
nr = 5;
k=0;
srand(time(NULL));
char v[20];
int l;
j=0;
pid_t pid;
for (i=1;i<sizeof(buffer);i++){
if (k == nr) break;
if (buffer[i]=='\n'){
k++;
pid = fork();
if (pid < 0)
return errno;
if (pid == 0){
//for (l=0;l<j;l++)
write (out, v, j);
return 0;
}
j=0;
}
else{
j++;
v[j-1]=buffer[i];
}
}
return 0;
}
Each of your child processes is writing to the same output stream, and they're all running concurrently, so their outputs are mixed together.
Instead of writing one character at a time, write the whole line. Calls to write() to a local POSIX-conforming filesystem are atomic, so you won't get data mixed between each process.
So change the loop:
for (l=0;l<j;l++)
write (out, v+l, 1);
to
write(out, v, j);
See Atomicity of `write(2)` to a local filesystem for various caveats about this.

Unable to kill processes running concurrently

I am running a program A.c concurrently, say 5 times. A part of the code is given below:
int main(int argc, char *argv[]){
char s = 0;
int i = 0;
pid_t procB_id = 0;
int retval = 0;
struct sigaction act;
ch = &c[0];
memset(c, 0, 50);
// open the file entered in the command-line for reading
fptr = fopen(argv[1], "r");
if(fptr == NULL){
printf("Error - input file could not be opened for reading!\n");
exit(EXIT_FAILURE);
}
// Write characters read by file pointer to an array
while((s=fgetc(fptr)) != EOF){
ch[i] = s;
i++;
}
printf("Length of text: %d\n",i);
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = handlerA;
if((sigaction(SIGRTMIN, &act, NULL)) != 0){
printf("Signal could not be registered!\n");
}
//get PID of daemon B to be able to send it a real-time signal, indicating that A has started
procB_id = getBprocessID();
printf("PROCESS ID OF B: %d\n", (int) procB_id);
//call sendSignal() method to send real-time signal to B
retval = sendBSignal(procB_id);
if(retval == 1){
while(n < 0){
//printf("BEFORE PAUSE\n");
pause();
}
//writeToFIFO(n);
if(writeToFIFO(n) == 1){
n = -1;
exit(EXIT_SUCCESS);
}
}
while (1);
}
The relevant part of the code is really exit(EXIT_SUCCESS). However, when I am running the process A in parallel, only 1 process is exiting, not the rest. The others are still running.
I am running the process in parallel by the following shell script:
for ((i=1;i<=5;i++))
do
./A file.txt &
done
"file.txt" is a file each process has to read separately. I want to kill all 5 processes, not just one. Does anyone know how I can do that? Please help. I guess my code is not correct, but I don't know what to do here.
I want to kill all 5 processes, not just one. Does anyone know how I can do that?
pkill -f "A file.txt"
You probably lost a do loop for your infinite while(1):
do {
procB_id = getBprocessID();
printf("PROCESS ID OF B: %d\n", (int) procB_id);
//call sendSignal() method to send real-time signal to B
retval = sendBSignal(procB_id);
if(retval == 1){
while(n < 0){
//printf("BEFORE PAUSE\n");
pause();
}
//writeToFIFO(n);
if(writeToFIFO(n) == 1){
n = -1;
exit(EXIT_SUCCESS);
}
}
} while (1);

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.

Reading File and enforcing order of operation between processes

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.

C Programming pipe only half working

I'm working on a mini shell for a college assignment. We have to read in the command, find the binary to execute from the path var, and execute command, both with and without pipes. I have everything working (I think) except for the pipe.
Through web searches I've been able to build a test program that use two hard coded commands and pipes one to the other, with the expected results. Now when I copy and paste that code into my actual program, the first command outputs fine (actually outputs the command as if there were no pipe), while the second I don't think actually does anything (the output from the first is not piped through to the second).
Here is the entire code:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#define BUFFSIZE 1024
#define MAXWORDS 17
#define MAXCHAR 64
static char *path;
extern char **environ;
//split cmd "string" on pipe (|) symbol
void split(char **pipe, char **left, char **right, int n)
{
int i, x;
for(i = 0; i < n; i++)
{
if (strchr(&pipe[i][0], '|') != 0)
{
for(x = 0; x < i; x++)
strcpy(left[x], pipe[x]);
left[x++] = 0;
break;
}
}
i++;
for(x = 0; i < n; x++)
strcpy(right[x], pipe[i++]);
right[x++] = 0;
}
//Find directory where cmd can be executed from (PATH or direct access)
char *finddir(char *s)
{
char *pp;
char *pf;
int ok;
strcpy(path, getenv("PATH"));
pp = strtok(path, ":");
while (pp != NULL)
{
pf = (char *)malloc(strlen(pp) + strlen(s) + 2);
if (pf == NULL)
{
fprintf(stderr, "Out of memory in finddir\n");
return NULL;
}
strcpy(pf,pp);
strcat(pf,"/");
strcat(pf,s);
ok = !access(pf, X_OK);
free(pf);
if (ok)
return pp;
pp = strtok(NULL, ":");
}
return NULL;
}
int cmdcheck(char *cmd, char *p)
{
char *dir;
if (strchr(p, '/') != NULL)
sprintf(cmd, "%s\0", p);
else
{
dir = finddir(p);
if (dir == NULL)
return 1;
else
sprintf(cmd, "%s/%s\0", dir, p);
}
return 0;
}
void runpipe(int pfd[], char *cmd1, char *p1[], char *cmd2, char *p2[])
{
int pid;
int status;
switch (pid = fork())
{
case 0: //Child
dup(pfd[0]);
close(pfd[1]); //the child does not need this end of the pipe
execve(cmd2, p2, environ);
perror(cmd2);
default: //Parent
dup(pfd[1]);
close(pfd[0]); //the parent does not need this end of the pipe
execve(cmd1, p1, environ);
perror(cmd1);
case -1: //ERROR
perror("fork-RP");
exit(1);
}
}
int main(void)
{
int status; //read status when reading cmd in
char ch; //character currently reading
int n, i, x; //(n) count of chars read; (i) cmd args iter; (x) cmd arg iter in cmd array
char buffer[BUFFSIZE]; //read buffer
char *token; //token var when splitting buffer
int pid0, pid1, pid2; //return ID from fork call
int which; //return value from wait (child pID that just ended)
char msg[100]; //messages to print out
char *cmd1, *cmd2; //cmds when piping
char *params[MAXWORDS]; //cmd parameters to send to execve
int fd[2]; //pipe file descriptors
char *pparam1[MAXWORDS]; //cmd "string" on left side of pipe
char *pparam2[MAXWORDS]; //cmd on right side of pipe
for(;;)
{
for (i = 0; i < MAXWORDS; i++)
params[i] = malloc(MAXCHAR);
n = 0;
write(1, "# ", 2);
for(;;)
{
status = read(0, &ch, 1);
if (status == 0)
return 0; //End of file
if (status == -1)
return 1; //Error
if(n == BUFFSIZE)
{
write(1, "Line too long\n", 14);
return 1;
}
buffer[n++] = ch;
if(ch == '\n')
break;
}
buffer[n] = '\0';
x = 0;
token = strtok(buffer, " \t\n\0");
while(token != NULL)
{
strcpy(params[x++], token);
token = strtok(NULL, " \t\n\0");
}
params[x] = 0;
path = getenv("PATH");
if (path == NULL)
{
fprintf(stderr, "PATH environment variable not found.\n");
return 1;
}
n = strlen(path);
path = (char *)malloc(n+1);
if (path == NULL)
{
fprintf(stderr, "Unable to allocate space for copy of PATH.\n");
return 1;
}
cmd1 = malloc(MAXCHAR);
cmd2 = malloc(MAXCHAR);
for (i = 0; i < MAXWORDS; i++)
pparam1[i] = malloc(MAXCHAR);
for (i = 0; i < MAXWORDS; i++)
pparam2[i] = malloc(MAXCHAR);
split(params, pparam1, pparam2, x);
//Check first cmd
if(cmdcheck(cmd1, pparam1[0]))
{
sprintf(msg, "cmd '%s' is not executable\n", pparam1[0]);
write(1, msg, strlen(msg));
break;
}
//Check second cmd
if(cmdcheck(cmd2, pparam2[0]))
{
sprintf(msg, "cmd '%s' is not executable\n", pparam2[0]);
write(1, msg, strlen(msg));
break;
}
pipe(fd);
switch (pid0 = fork())
{
case 0: //Child
switch (pid1 = fork())
{
case 0: //Child
runpipe(fd, cmd1, pparam1, cmd2, pparam2);
exit(0);
default:
exit(0);
//break;
case -1: //ERROR
perror("fork-2");
exit(1);
}
default: //Parent
which = wait(&status);
if (which == -1)
{
write(1, "wait failed\n", 12);
exit(1);
}
if (status & 0xff)
sprintf(msg, "process %d terminated abnormally for reason %d\n", which, status & 0xff);
else
sprintf(msg, "process %d terminated normally with status %d\n", which, (status >> 8) & 0xff);
write(1, msg, strlen(msg));
break;
case -1: //ERROR
perror("fork-1");
exit(1);
}
free(cmd1);
free(cmd2);
for (i = 0; i < MAXWORDS; i++)
free(pparam1[i]);
for (i = 0; i < MAXWORDS; i++)
free(pparam2[i]);
free(path);
for (i = 0; i < MAXWORDS; i++)
free(params[i]);
}
return 0;
}
Typing echo one | wc -l at the prompt will only output one with the respective wait print statement following. It has been a few years since I've used C, so am I on the right track?
Thanks.
EDIT:
Here is the runpipe function as it stands now. But the only thing that is printed is the wait statement.
void runpipe(int pfd[], char *cmd1, char *p1[], char *cmd2, char *p2[])
{
const int READ = 0;
const int WRITE = 1;
int pid;
int status;
switch (pid = fork())
{
case 0: //Child
close(pfd[WRITE]);
dup2(pfd[READ], STDIN_FILENO);
close(pfd[READ]);
execve(cmd2, p2, environ);
perror(cmd2);
default: //Parent
close(pfd[READ]);
dup2(pfd[WRITE], STDOUT_FILENO);
close(pfd[WRITE]);
execve(cmd1, p1, environ);
perror(cmd1);
case -1: //ERROR
perror("fork-RP");
exit(1);
}
}
There are a couple of things going on there that are contributing to the unexpected behavior.
The first is that you're forking too much. If you unroll your runpipe() function call into the switch statement in main(), you'll see that you reach the great-grandchild level:
switch (pid0 = fork())
{
case 0: // Child
switch (pid1 = fork())
{
case 0: // GRAND-Child
// function call to runpipe()
switch (pid = fork())
{
case 0: // GREAT-GRAND-Child
close(pfd[WRITE]);
dup2(pfd[READ], STDIN_FILENO);
close(pfd[READ]);
execve(cmd2, p2, environ);
perror(cmd2);
default: // GRAND-Child
close(pfd[READ]);
dup2(pfd[WRITE], STDOUT_FILENO);
close(pfd[WRITE]);
execve(cmd1, p1, environ);
perror(cmd1);
Which is not necessary. Fork once in main() and then call your runpipe() function.
Related to this issue is where you're creating your pipe. When you fork, the newly created child process inherits all of the parent process's open files (among many other things). This includes the default descriptors 0, 1, and 2 (stdin, stdout, and stderr), as well as any other open files, including the pipe you created called fd. This means that the parent, child, grandchild, and great-grandchild are all inheriting a copy of both ends of the pipe. You correctly close the unused ends inside the runpipe() function (the grandchild's and great-grandchild's copies), but the parent and child in your main() function also have copies!
Since the only pair of processes using the pipe are those created in runpipe(), you can move the declaration of fd and the call to pipe(2) into that function.
These two modifications will resolve your issues.
A completely unrelated issue that just relates to the flow of your shell is that your main() ends up doing its wait(2) on the "parent" process of the runpipe() function. Since that parent is the one running cmd1, your shell is going to return its prompt as soon as cmd1 finishes, instead of when the last command (cmd2 in this case) in the pipeline finishes. You can see the behavioral difference by running something like echo | sleep 10 into your shell and a real shell.
The dup function duplicates a file descriptor, and returns the new duplicate. However, this will not work, as stdin in the child still exists, and the new file descriptor will not be put in place of the standard input.
You must close the standard input file descriptor first, before doing dup. Or use dup2 which will close the destination file descriptor automatically first before doing the duplication:
dup2(pfd[0], STDIN_FILENO);

Resources