views:

76

answers:

3

Hi every one !

I have a little problem. I have to code a simple C application that creat a process and his child (fork()) and I have to do an operation. Parent initialize the values and child calculate. I write this :


#include <stdlib.h>
#include <signal.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>



typedef struct {
    int op1;
    char op;
    int op2;
}Operation;

Operation *varOP;

void finalResult()
{
    float result = 0;
    if(varOP->op == '+') result = (varOP->op1 + varOP->op2);
    if(varOP->op == '-') result = (varOP->op1 - varOP->op2);
    if(varOP->op == '*') result = (varOP->op1 * varOP->op2);
    if(varOP->op == '+') result = (varOP->op1 / varOP->op2);

    printf("%f",result);
}

int main () {

    int p;

    varOP  = (Operation *)malloc(sizeof(Operation));
    p = fork();


    if(p == 0) // If child
    {
        signal(SIGUSR1, finalResult );
        pause();
    }

    if(p > 0) // If parent
    {
        varOP->op = '+';
        varOP->op1 = 2;
        varOP->op2 = 3;
        kill(p, SIGUSR1);
        wait(NULL);
    }

    return 0;
}

But my child is never called. Is there something wrong with my code? Thanks for your help !

A: 

It may be that the child has not yet executed the signal() call when the parent calls kill().

Didier Trosset
Yes I agree with you but I don't know how to resolve it :(
Pierre
You could send a signal from the child to the parent.
Rudi
yes but I don't think it's the solution because this is the child which must be read at the end. I'm a little bit lost ...
Pierre
You can simply add a call to `sleep(1)` at the start of the parent block. This way you can make sure* that the child is ready when you kill. (*sure at 99.9999999 %) Maybe `sleep(0)` could do the trick?
Didier Trosset
+2  A: 

Your sample code also has a more fundamental problem: each process has its own data space, and so your technique of sending information to the child via the heap will not work. One solution is to use a pipe. This adds only four more lines to your code:

typedef struct {
    int op1;
    char op;
    int op2;
}Operation;

Operation *varOP;

static int pipe_fds[2]; /* <-- added */

static void finalResult(void)
{
    float result = 0;
    read(pipe_fds[0], varOP, sizeof(Operation)); /* <-- added */
    if(varOP->op == '+') result = (varOP->op1 + varOP->op2);
    if(varOP->op == '-') result = (varOP->op1 - varOP->op2);
    if(varOP->op == '*') result = (varOP->op1 * varOP->op2);
    if(varOP->op == '/') result = (varOP->op1 / varOP->op2); /* <-- typo */

    printf("%f\n",result);
}

int main (void) 
{
    int p;
    pipe(pipe_fds); /* <-- added */
    varOP = (Operation *)malloc(sizeof(Operation)); 
    p = fork();

    if(p == 0) // If child
    {
        signal(SIGUSR1, finalResult );
        pause();
    }

    if(p > 0) // If parent
    {
        varOP->op = '+';
        varOP->op1 = 2;
        varOP->op2 = 3;
        write(pipe_fds[1], varOP, sizeof(Operation)); /* <-- added */
        kill(p, SIGUSR1);
        wait(NULL);
    }

    return 0;
}
Joseph Quinsey
I tried your solution, it's working well. Thanks ! I posted a code that use memory segmentation but unsuccessful :(
Pierre
It would be more reliable to dispense with the signal handler altogether and just directly call the `finalResult()` function where the child currently calls `signal(); pause();`. The pipe will take care of synchronisation in this case; with the current code, the child can miss the signal because there is no guarantee that it will execute `signal()` before the parent executes `kill()`.
caf
@caf: I agree with both your points: signals are unnecessary and arguably wrong here, and the code is incorrect by calling signal() too late. I did mean to mention the second, and it could be the cause of the original issue--'my child is never called'--but instead just focused on the primary misconception, which is surprising widespread.
Joseph Quinsey
And of course printf() is **not** a POSIX.1 safe function for signal handlers.
Joseph Quinsey
A: 

Thanks Joseph it is working well ! I'm tried to do it with memory segementation and I have the same problem -_-


#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 

typedef struct {
    int op1;
    char op;
    int op2;
}Operation;


int id;

void hand()
{
    Operation *varOP  = (Operation*) shmat(id, NULL, SHM_R); 
    shmdt((char *) varOP):
    float result = 0;

    switch (varOP->op) {
        case '+':
            result = (varOP->op1 + varOP->op2);
            break;
        case '-':
            result = (varOP->op1 - varOP->op2);
            break;
        case '*':
            result = (varOP->op1 * varOP->op2);
            break;
        case '/':
            result = (varOP->op1 / varOP->op2);
            break;
        default:
            result = 0;
            break;
    }

    printf("%f",result);
    exit(0);
}

int main () {

    int p;
    key_t cle;

    p = fork();

    cle = ftok(getenv("titi"), 'A');
    id = shmget(cle, sizeof(Operation),0);

    if(p == 0) // Si fils
    {
        signal(SIGUSR1,hand);
        while (1);
        exit(0);
    }

    if(p > 0)
    {
        Operation *varOP  = (Operation*) shmat(id, NULL, SHM_W); 
        varOP->op = '+';
        varOP->op1 = 2;
        varOP->op2 = 3;
        shmdt((char *) varOP);
        kill(p, SIGUSR1);

        wait(NULL);
    }

    return 0;
}
Pierre
I think the problem here is that in hand() you are calling shmdt() too soon (in testing with CYGWIN).
Joseph Quinsey
Yes you are right. It's good now. Thanks !
Pierre