2

My question is, how can I pass the X value between process, I don't wanna use a global variable for this.

int main(int argc, char *argv[])
{
    pid_t pid;
    int x;
    x = 1;
    pid=fork();
  // Daqui para baixo executa o fork
  if (pid == 0){ //Processo filho
    printf("Processo Filho\n");
    x = x + 2;
    printf("Somando 2 ao X, temos: %d\n", x);

    exit(0);
    }
    
    else
    { //Processo pai
    printf("Processo pai\n");
    printf("O valor inicial de X é: %d\n", x);
    wait(NULL);
    x = x * 4;
    printf("Agora multiplicando o valor de X por 4 temos: %d\n", x);
    printf("Criança completa\n");
    }
  return 0;
}

I'm trying just to print the X value using the shmget, but I get -1, I'm currently just testing if I can pass the X value using that

int main(int argc, char *argv[])
{
    pid_t pid;
    int x;
    int shmid;
    int *shmptr;
    x = 1;
    shmid = shmget(x, 4*sizeof(int), IPC_CREAT | 0666);
    shmptr = (int *) shmat(shmid, NULL, 0);
    pid=fork();
  // Daqui para baixo executa o fork
  if (pid == 0){ //Processo filho
    printf("Processo Filho\n");
    printf("%d\n",shmid);
    x = x + 2;
    printf("Somando 2 ao X, temos: %d\n", x);

    exit(0);
    }
    
    else
    { //Processo pai
    printf("Processo pai\n");
    printf("O valor inicial de X é: %d\n", x);
    wait(NULL);
    x = x * 4;
    printf("Agora multiplicando o valor de X por 4 temos: %d\n", x);
    printf("Criança completa\n");
    }
  return 0;
}

2 Answers2

4

When you fork, you are creating a process that is an exact copy of the current process. It also copies data so you have access to the exact same things you have on the main process except the pid (the return of the call to fork()).

So your x value is copied. If you change it in the child process it will not be changed in the parent process even if you are using global variables

int x = 0;
pid = fork();
if (pid == 0) // Child process
{
    printf("%d\n", x); // will print 0
    x++;
}
else
{
    printf("%d\n", x); // Will print 0
}
printf("%d\n", x); // Will print 0 in the parent process and 1 in the child process

If you want to retrieve your X value from the child process you should look to the waitpid function.

Here is an example on how to use it:

int pid = fork();

if (pid == -1)
    exit(1);

if (pid == 0) // Child
{
    exit(42);
}

int wstatus;
if (waitpid(pid, &wstatus, 0) == -1)
    exit(1);
if (!WIFEXITED(wstatus))
    exit(1);

printf("process exit status: %d\n", WEXITSTATUS(wstatus)); // 42

Eron
  • 134
  • 3
  • You can use the exit status, but on POSIX systems, that only allows values in the range 0..255. You are mostly out of luck if you need to pass back bigger values (or negative values). (You can look at `sigaction()`, signal handlers, `SIGCLD`, and `SA_SIGINFO` if you want.) – Jonathan Leffler Mar 04 '22 at 23:40
  • Couldn't a block of memory be shared between two or more processes? For Windows this can be done with a named or unnamed mapped memory file. The handle of an unnamed memory file can be passed as a parameter when creating other processes. In the case of Windows, each process may get a different address for the shared mapped memory file, so containers like linked lists need to use offsets from base of mapped memory file as opposed to normal pointers. – rcgldr Mar 05 '22 at 00:31
  • @JonathanLeffler I'm pretty sure the ability to return exit status values greater than 255 is broken on Linux. When I run `strace` against a process that exits with `exit(12345)`, I see this on Ubuntu 20.04: `[pid 3173591] exit_group(12345) = ?` and then `[pid 3173591] +++ exited with 57 +++` on the next line. Note that `12345` was truncated to `57`, `12345 % 256` equals `57`. The parent process receives a value of `57` in the `si_status` field of the `siginfo_t` structure. It appears Linux truncates the return value to 8 bits somewhere in the exit processing. – Andrew Henle Mar 05 '22 at 01:50
  • @JonathanLeffler Yep, [Linux is broken](https://github.com/torvalds/linux/blob/763978ca67a3d7be3915e2035e2a6c331524c748/kernel/exit.c#L944) : `do_group_exit((error_code & 0xff) << 8);` On Linux, all but the low-order 8 bits are discarded in the kernel when the process exits. – Andrew Henle Mar 05 '22 at 02:06
  • Thanks, @AndrewHenle — Fortunately, all the world is not Linux (yet). It works OK on macOS and hence, presumably, the BSD family. – Jonathan Leffler Mar 05 '22 at 05:33
  • @JonathanLeffler It's fine on Solaris, too. – Andrew Henle Mar 05 '22 at 11:18
  • @AndrewHenle — so, where I said "mostly out of luck", you are upgrading it to "totally out of luck (on Linux)", with the side-comment "some other POSIX-compliant systems would allow you to do it, though it is not particularly convenient on those other systems". Windows allows larger exit code automatically, I believe, for all it seems to encourage the use of `void main()` (though I suppose it prefers, even more, its non-standard variations on the theme of `main()`). – Jonathan Leffler Mar 05 '22 at 18:20
  • @JonathanLeffler I'm not sure I'm willing to accept the blame for this. ;-) But yes, on Linux you can't get more than 8 bits of exit return value no matter what POSIX says. I was sure there was a question on this where the breakage was pointed out in an answer, but I can't seem to find it. – Andrew Henle Mar 05 '22 at 18:50
  • @rcgldr: yes, certainly shared memory could be used to coordinate and communicate between processes — so could pipes, files, FIFOs, sockets and message queues, to name but a few other options. With all of these, the issue is "how does the child know about the communication method". Clearly, if there is no `exec*()` involved, there's no difficulty, but if you execute a child, how does it know which resource to use for communication? And so it goes on. (And I attached no blame to you — it is useful to know that Linux is not as helpful as other platforms in this minor detail.) – Jonathan Leffler Mar 05 '22 at 19:50
2

On POSIX systems it's also possible to use real-time signals to send up to 64 bits of data between processes. Per POSIX 7 2.4.2 Realtime Signal Generation and Delivery:

This section describes functionality to support realtime signal generation and delivery.

Some signal-generating functions, such as high-resolution timer expiration, asynchronous I/O completion, interprocess message arrival, and the sigqueue() function, support the specification of an application-defined value, either explicitly as a parameter to the function or in a sigevent structure parameter. The sigevent structure is defined in <signal.h> and contains at least the following members:

Member Type            Member Name             Description

int                    sigev_notify            Notification type.
int                    sigev_signo             Signal number.
union sigval           sigev_value             Signal value.
void(*)(union sigval)  sigev_notify_function   Notification function.
(pthread_attr_t*)      sigev_notify_attributes Notification attributes.

...

The sigval union is defined in <signal.h> and contains at least the following members:

Member Type            Member Name             Description

int                    sival_int               Integer signal value.
void*                  sival_ptr               Pointer signal value.

The sival_int member shall be used when the application-defined value is of type int; the sival_ptr member shall be used when the application-defined value is a pointer.

Sending the value is simple:

int value = ...;

union sigval sv;
memset( &sv, 0, sizeof( sv ) );
sv.sival_int = value;

int rc = sigqueue( pid, SIGRTMAX, sv );

On a system with 64-bit pointers, you can hack the use of the sival_ptr pointer field to send 64 bits of data:

uint64_t value = ...;

union sigval sv;
memset( &sv, 0, sizeof( sv ) );
sv.sival_ptr = ( void * )( uintptr_t ) value;

int rc = sigqueue( pid, SIGRTMAX, sv );

You can use a signal handler to retrieve the value:

void handler( int sig, siginfo_t *info, void *context )
{
    int value = info->si_value.sival_int;

    ...
}

...

struct sigaction sa;

memset( &sa, 0, sizeof( sa ) );

sa.sa_sigaction = handler;
sa.sa_flags = SA_RESTART | SA_SIGINFO;

sigaction( SIGCHLD, &sa, NULL );

Or, using sigwaitinfo():

sigset_t sigSet;
memset( &sigSet, 0, sizeof( sigSet ) );
sigemptyset( &sigSet );

sigaddset( &sigSet, SIGRTMAX );

sigprocmask( SIG_BLOCK, &sigSet, NULL );

siginfo_t siginfo;

int sigNum = sigwaitinfo( &sigSet, &siginfo );
if ( SIGRTMAX == sigNum )
{
    int value = siginfo.si_value.sival_int;

    ...
}
Andrew Henle
  • 32,625
  • 3
  • 24
  • 56