pospolitaki
pospolitaki

Reputation: 353

Why the value of the `volatile` variable doesn't change?

I'm trying to understand basics of C, volatile keyword exactly.

It doesn't seem to work as I thought. I read somewhere:

volatile specifies that value associated with the var can be modified by action other than those in the nearby code. When a var is declared volatile, the compiler reloads the value from
memory each time it is accessed by the program. This prevents optimization by optimizing compilers. It's mainly used to ensure predictable program behavior.

I've got two programs, compiled from two different .c files.

start_loop has global int variable called done with 0 as initial value and infinite loop which should test if done value have been changed to 1. Also it outputs address of the done variable to stdout.

start_loop program:

#include <stdio.h>
#include <time.h>

volatile int done = 0;
void delay(int seconds){
    // some logic for time delay here
    }

void main() {
    while (done !=1){
        delay(4);
        printf("adress of `done`: %p\nvalue: %d\n", &done, done);
    }
}

And change_done_var_value program which should get the address of the done variable as main argument and change it from 0 to 1.
Thus infinite loop in start_loop program should check value of done and exit the program.

change_done_var_value:

#include <stdio.h>
#include <stdlib.h>

void main(int argc, char *argv[])
{
    char *str_arg_done = argv[1];
    long int done_addr = (int)strtol(str_arg_done, NULL, 16);
    long int *done = (long int *)done_addr;  // converting str to pointer
    printf("got the address as first arg(str): %s -> address/value %p/%li\n", argv[1], done, *done);
    printf("change `done` to 1?\n");
    char answer = fgetc(stdin);
    if (answer == 'y')
    {
        *done = 1;
        printf("changed\nnew value: %li", *done);
    }
    else
    {
        printf("canceled\n");
}

As i've started the start_loop program in first terminal tab i got:

4 seconds delay passed
#1
adress of `done`: 0x601048
value: 0

4 seconds delay passed
#2
adress of `done`: 0x601048
value: 0

...

In the second terminal tab i started the change_done_var_value and passed 0x601048 to it:

got the address as first arg(str): 0x601048 -> adress/value 0x601048/0
change `done` to 1?
y
changed
new value: 1

But start_loop program still runs:

4 seconds delay passed
#46
adress of `done`: 0x601048
value: 0

It seems that the change_done_var_value program got the right address value cause it shows right 0 value while dereferencing pointer to done variable..

What do i need to do to make things work(to change value of done from change_done_var_value and stop the executing of thestart_loop program)? Or it doesn't work like this..

Upvotes: 0

Views: 764

Answers (2)

ChrisoLosoph
ChrisoLosoph

Reputation: 607

If I understand right, you try to use memory from one program in another program? "It doesn't work like this" on any modern operating system because programs (or better: "processes") are encapsulated purposefully this way that they can't access the memory of other processes without operating-system-specific interprocess communication library functions. You can read more about them and how to use them in C in a Linux-based operating system on this website:

Linux Interprocess Communications

I'm sorry that I can't elaborate further since I never used internal interprocess communication on a common Desktop Operating System yet.

There is also a more heavy-weight option to use the socket API (which generally can be used even accross a network of distinct PCs all over the world). Using the socket API is not difficult and is taught in network lecture courses in university. You then get "server" and "client" programs and you have to take care about some "primitives" which must be called in a specific order. A common source of tutorials seems to be the Beej Guide .

This protection mechanism is called memory virtualization. It makes that every process uses its very own virtual address space which is not equal to the one of other processes. Or brief: the same addresses in different programs will lead to separate physical addresses in the real memory.

In my opinion the design mistake here is to compile two different programs to achieve the task. The usual appraoch would be to compile only one single program which uses multi-threading (that means multiple threads of execution) because multi-threading is more light-weight than interprocess communication and maybe easier to use (at least I know how to do it). For multi-threading, you can use the pthread library in Linux-based systemes which can be included into your program with the -pthread command line option when I remember correctly).

Happy coding!

Upvotes: 3

Karl Knechtel
Karl Knechtel

Reputation: 61519

action other than those in the nearby code

Yes; this means things that are able to modify the corresponding chunk of memory. Most often, this will be a different thread within the same program. In some very specific platform-specific circumstances, you might arrange for a variable to be in a specific location that has a special meaning to the OS (or to the hardware); for example, on an old handheld or console you could read from a virtual memory location that represents an I/O register, in order to learn what button was pressed on the keypad. By using volatile, the compiler will understand that the value has to be checked, because the hardware may have written to that memory and your program depends on knowing about the change.

On a modern desktop computer, programs have memory protection and memory space virtualization. They cannot easily look at each others' data, and will typically need some special arrangement/permission to do so. But even when it is possible, you cannot simply check on the other program's variable by using its name - the name is only meaningful to the compiler; it is not an actual part of the compiled program (although a debug-mode compilation might try to make it behave that way a little bit).

Upvotes: 4

Related Questions