Why are my semaphores not working as expected? - c

I need to print the following sentence to the console "My name is Bond, James Bond" alternating the words using semaphores.
Whenever I print the words using line breaks "\n", everything prints in the expected order, however if I don't use line breaks everything prints out of order.
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <wait.h>
#include <unistd.h>
#include <semaphore.h>
#include <string.h>
int main(){
pid_t pid;
int i = 0;
sem_t *sem[4];
char * names[4] = {"/sem_ex07_1", "/sem_ex07_2", "/sem_ex07_3", "/sem_ex07_4"};
for(i = 0; i < 4; i++){
sem_unlink(names[i]);
}
for(i = 0; i < 4; i++){
if((sem[i] = sem_open(names[i], O_CREAT | O_EXCL, 0644, 0)) == SEM_FAILED){
printf("sem_open() error\n");
sem_unlink(names[i]);
exit(1);
}
}
sem_post(sem[0]);
for(i = 0; i < 3; i++){
pid = fork();
if(pid == 0){
break;
}
}
if(pid == 0){
if(i == 0){
sem_wait(sem[0]);
printf("My");
sem_post(sem[1]);
sem_wait(sem[0]);
printf("Bond, ");
sem_post(sem[1]);
} else if(i == 1){
sem_wait(sem[1]);
printf("name ");
sem_post(sem[2]);
sem_wait(sem[1]);
printf("James ");
sem_post(sem[2]);
} else if(i == 2){
sem_wait(sem[2]);
printf("is ");
sem_post(sem[0]);
sem_wait(sem[2]);
printf("Bond.\n");
sem_post(sem[3]);
}
} else if(pid > 0){
sem_wait(sem[3]);
for(i = 0; i < 4; i++){
sem_unlink(names[i]);
}
}
return 0;
}
Why is my output only correct if I add a line break on each printf?

Why is my output only correct if I add a line break on each printf?
printf() is mostly by default line buffered. stdio functions which use streams (instead of file descriptors like write() does) use a buffer.
The buffer can be set via setvbuf(3).
See also Disable buffering for stdin and stdout using setvbuf()

Related

Formating execvp output

I am working on a shell command program in C, I have it working but the output is not formatted correctly. I am unable to see where the problem lies. I have read through the code several times and I am not seeing the issue. I have tried placing \n in various places but that typicality results in worse formatting.
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <wait.h>
#include <stdlib.h>
#include <termios.h>
#include <fcntl.h>
#define MAX_LINE 80 /*Maximum length of a command*/
#define MAX_HST 10
int main(void){
char getInput[MAX_LINE];
char *args[MAX_LINE/2+1]; /*command line arguments*/
int should_run = 1; /*Flag to determine when to exit the program*/
int numCommand = 0;
int cmdHst = 0;
char *cmdHistory[MAX_HST];
char *myCmd;
while (should_run = 1){
printf("osh> ");
fflush(stdout);
fgets(getInput, MAX_LINE, stdin);//read input command
if(strcmp(getInput, "!!\n") == 0){//Command history
if(cmdHst == 0){
printf("No previous commands.\n");
}
for (int i= 0; i<cmdHst; i++){//display all commands in history
strncpy(getInput, cmdHistory[i], MAX_LINE);
printf("%s\n", getInput);
}
}
if (cmdHst < MAX_HST){
cmdHistory[cmdHst] = strdup(getInput);
cmdHst++;
}
else{//shift commands in history to fill gaps
for(int i = 1; i < cmdHst; i++){
free(cmdHistory[i-1]);
cmdHistory[i-1]= strdup(cmdHistory[i]);
}
free(cmdHistory[cmdHst-1]);
cmdHistory[MAX_HST-1] = strdup(getInput);
}
//parsing commands into tokens
numCommand = 0;
args[numCommand] = strtok(getInput, " \n");
while(args[numCommand] != NULL){
numCommand++;
args[numCommand] = strtok(NULL, " \n");
}
args[numCommand]=NULL;
if(strcmp(args[0], "exit")==0){//Check for exit command
should_run =0;
break;
}
pid_t pid = fork();//Create child process
if(pid < 0){
fprintf(stderr, "Fork Failed\n");
return 1;
}
else if(pid == 0){
if(execvp(args[0], args)==-1){
fprintf(stderr, "Command Not Found.\n");
exit(1);
}
else{
if(args[numCommand-1][0] != '&'){
wait(NULL);
}
}
}
}
for(int i = 0; i < cmdHst; i++){//free histrry array
free(cmdHistory[i]);
}
return 0;
}
I have read over the code a few times and tried in putting fprintf("\n");s in various places.
I forgot the parent wait(NULL) command. That fixed it.

Taking an exact number of bytes from input in C and synchronization between processes

Hi i need to take only 5 bytes from stdin, i've tried this but i have problem while executing it since it keeps asking me for input and at the end the string contained in buffer is wrong.
Also i'd like to know how to synchronize N processes while the parent is sleeping.
buffers[] is an array of buffers.
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/mman.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define fflush(stdin) while (getchar() != '\n')
char **filenames;
int *files;
char **buffers;
int n_proc;
int main(int argc, char **argv) {
long i;
pid_t pid;
int status;
if(argc < 2) {
puts("Usage error: prog file1 ... fileN.\n");
exit(1);
}
filenames = argv + 1;
n_proc = argc - 1;
puts("Bef malloc buff.\n");
if((buffers = malloc(sizeof(char *) * n_proc)) == NULL) {
puts("Buffers' malloc error.\n");
exit(1);
}
if((files = malloc(sizeof(int) * n_proc)) == NULL) {
puts("Files' malloc error.\n");
exit(1);
}
puts("After malloc buff.\n");
for(i = 0; i < n_proc; i++) {
if((files[i] = open(filenames[i], O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) {
printf("Error while opening file %ld.\n", i);
exit(1);
}
}
puts("After file open.\n");
for(i = 0; i < n_proc; i++) {
if((buffers[i] = (char *) mmap(NULL, 1028, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0)) == NULL) {
printf("Error in mapping buffer %ld.\n", i);
exit(1);
}
}
puts("After mapping.\n");
i = 0;
while(i < n_proc) {
printf("Fork %ld started.\n", i);
pid = fork();
if(pid < 0) {
printf("Error while forking %ld.\n", i);
exit(1);
} else if(pid == 0) {
puts("Please insert an input of max 5 characters.\n");
printf("Son %ld.\n", i);
fflush(stdout);
fgets(buffers[i], 6, stdin);
buffers[i][strcspn(buffers[i], "\n")] = 0;
//int j;
//for(j = 0; j < 5; j++)
//buffers[i][j] = getchar();
//printf("Buff has %s inside.\n", buff);
//fflush(stdout);
fflush(stdin);
//strcpy(buffers[i], buff);
printf("Buffer %d has string %s inside.\n", i, buffers[i]);
fflush(stdout);
write(files[i], buffers[i], 6);
} else {
printf("Parent %ld.\n", i);
wait(&status);
}
i++;
}
}
This is only a prototype of the code, since there's still synchronization needed and signal handling
Code requires when to write on command line N files and creating N processes that each take 5 bytes from stdin and put in their own file.
As an example if i try with
./a.out hello.txt hello1.txt
Bef malloc buff.
After malloc buff.
After file open.
After mapping.
Fork 0 started.
Parent 0.
Please insert an input of max 5 characters.
Son 0.
Hello
Hello
Buffer 0 has string Hello inside.
Hello
Fork 1 started.
Parent 1.
Please insert an input of max 5 characters.
Son 1.
Hello
Hello
Buffer 1 has string Hello inside.
Hello
Fork 1 started.
Parent 1.
Please insert an input of max 5 characters.
Son 1.
As you can see it doesn't take the input and keeps asking for it, same problem with the getchar().
Note that in case stdin is associated with a terminal, there may also be input buffering in the terminal driver, entirely unrelated to stdio buffering. (Indeed, normally terminal input is line buffered in the kernel.) This kernel input handling can be modified using calls like tcsetattr(3); (stdin(3) man page)
If you give it the input "12345\n":
#include <stdio.h>
int main(void) {
char buffers[1][5];
unsigned i = 0;
for(unsigned j = 0; j < 5; j++)
buffers[i][j] = getchar();
printf("%.5s", buffers[i]);
// read the newline. You may need to discard others.
int ch = getchar();
if(ch == '\n')
printf("\n");
return 0;
}
it will print:
12345

How do I get keyboard inputs from the user using C and linux?

I have to make a short program that, creates two child processes, each one accepting an integer from the keyboard and writes them to a pipe, from where the parent process summarizes them and displays the total on the screen.
I've written one with scanf(), but it freezes up and it doesn't give me the sum. How do I make it work with scanf or any other way if possible?
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int pipe(int pd[2]);
int main(int argc, char *argv[])
{
int pd[2], sum=0, num=0;
if(pipe(pd) == -1)
for(int i = 0; i < 2; i++)
{
if(fork() == 0)
{
scanf("%d", num);
if(write(pd[1], &num, sizeof(int)) == -1)
printf("Error: Write()");
}
}
for(int j = 0; j < 2; j++)
{
wait(NULL);
if(read(pd[0], &num, sizeof(int)) == -1)
printf("Error: Read()");
sum += num;
}
printf("Total: %d\n", sum);
}
Lots of problems here:
You have if(pipe(pd) == -1), and I assume you meant to have an error handler as the "then" clause for it, but you don't, so children will only spawn if the pipe fails, which is basically the opposite of what you want.
You have scanf("%d", num);. You need &num since num isn't already a pointer.
You need to return or exit from the child processes, or they'll fall into the next loop and consume the output.
With just those things fixed, it's enough to make it work:
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int pipe(int pd[2]);
int main(int argc, char *argv[])
{
int pd[2], sum=0, num=0;
if(pipe(pd) == -1)
{
perror("pipe");
return 1;
}
for(int i = 0; i < 2; i++)
{
if(fork() == 0)
{
scanf("%d", &num);
if(write(pd[1], &num, sizeof(int)) == -1)
printf("Error: Write()");
return 0;
}
}
for(int j = 0; j < 2; j++)
{
wait(NULL);
if(read(pd[0], &num, sizeof(int)) == -1)
printf("Error: Read()");
sum += num;
}
printf("Total: %d\n", sum);
}
There's a few other things you should fix too, but they're not complete show-stoppers. Here's what jumped out at me:
You don't need to declare your own pipe prototype. The one from unistd.h is fine.
You should handle the case where fork or scanf fail.
You should handle partial reads and writes.
You should close the read end of the pipe in the children and the write end of the pipe in the parent after forking.
You should consider using a lock to control reading input, so that it doesn't depend on TTY line buffering to work reliably.

How is this Producer & Consumer using pipes example able to prevent a deadlock?

I'm taking a look at a Solution Example for Producer & Consumer problem, using pipes.
And I do not understand how it is preventing a race condition.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>
void producer(FILE *pipe_write_end)
{
int i;
for(i = 1; i <= 10; i++) {
fprintf(pipe_write_end, "%d ", i);
}
fclose(pipe_write_end);
exit(0);
}
void consumer(FILE *pipe_read_end)
{
int n,k;
while(1) {
int n = fscanf(pipe_read_end, "%d", &k);
if(n == 1) printf("consumer: got %d\n", k);
else break;
}
fclose(pipe_read_end);
exit(0);
}
int main()
{
pid_t producer_id, consumer_id;
int pd[2];
FILE *pipe_write_end, *pipe_read_end;
pipe(pd);
pipe_read_end = fdopen(pd[0], "r");
pipe_write_end = fdopen(pd[1], "w");
producer_id = fork();
if(producer_id == 0) {
fclose(pipe_read_end);
producer(pipe_write_end);
}
consumer_id = fork();
if(consumer_id == 0) {
fclose(pipe_write_end);
consumer(pipe_read_end);
}
fclose(pipe_read_end);
fclose(pipe_write_end);
wait(NULL);
wait(NULL);
return 0;
}
My current thinking is that the int n = fscanf(pipe_read_end, "%d", &k); is waiting for the producer to close the file, but I don't understand how.
If 2 Child Processes are created, 1 to consume, 1 to Produce
- How is it able to automatically just produce without error?

Using pipes to implement simple shell in c? [duplicate]

This question already has answers here:
Pipe implementation
(2 answers)
C Minishell Adding Pipelines
(1 answer)
Closed 8 years ago.
I am building a simple shell in c using fork and execlp. I will be given a set of commands separated by pipes. eg: ls -l | wc -l .
I want to use pipes for intra process communication. So the output from ls -l is input for wc -l. There can any number of commands separated by pipes. I am not understanding whether to create a pipe between a child process and parent and then when I get a output from a child process somehow transfer that output to another child process... I have parsed the inputs. How can I go about this?
void excueteCommands() {
int i, j;
int fd[2];
int cid1;
commandNode* ptr = head;
while (ptr != NULL) {
for (i = 0; i <= pipeCount; i++) {
cid1 = fork();
if (!cid1) {
if (i != 0) {
dup2(fd[i - 1][0], 0);
}
if (i != pipeCount) {
dup2(fd[i][1], 1);
}
for (j = 0; j < pipeCount; j++) {
close(fd[j][0]);
close(fd[j][1]);
}
execlp(ptr->command, ptr->args, NULL);
exit(0);
}
ptr = ptr->next;
}
}
for (i = 0; i < pipeCount; i++) {
close(fd[i][0]);
close(fd[i][1]);
}
}
I also had same assignment last year. Your need not to handle input and output from one process to another separately. Just initialize pipes between the series of processes and the flow of input and output would take place itself. You only need to give input to first command and take output from the last command.
Following is code snippet I used.
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
#include <unistd.h>
#include <stddef.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <sys/wait.h>
int exit_flag = 0;
#define ARG_SIZE 100
int main ()
{
int size = 1000,i,j;
int pipe_count = 0;
int fd[100][2],cid1,cid2,length,status;
char string[][100] = {"ls","wc"};
pipe_count = 1;
if(pipe_count)
{
for(i = 0;i < pipe_count;i++)
{
pipe(fd[i]);
}
for(i = 0;i <= pipe_count;i++)
{
cid1 = fork();
if(!cid1)
{
if(i!=0)
{
dup2(fd[i-1][0],0);
}
if(i!=pipe_count)
{
dup2(fd[i][1],1);
}
for(j = 0;j < pipe_count;j++)
{
close(fd[j][0]);
close(fd[j][1]);
}
execlp(string[i], string[i], NULL);
exit(0);
}
}
for(i = 0;i < pipe_count;i++)
{
close(fd[i][0]);
close(fd[i][1]);
}
waitpid(cid1,&status,0);
}
else
{
execlp(string[0], string[0], NULL);
}
return 0;
}
In above code string[] array contains all commands separated by '|' in sequence. fd[][2] is array of file descriptors. fd[i][0] is input of i+1 command and fd[i][1] is output of ith command. So output of i goes to input of i+1 using fd[i] pipe.
I don't remember now how the dup2 and close commands were handled. May you may get them since you have done them recently. I there is any doubt then I would try my best to clarify.

Resources