Short answer: Yes it's possible for each thread to have its own copy of the variable i
.
Long answer:
All threads share the same address space and the OS does not provide any protection to prevent one thread from accessing memory used by another. However, the memory can be partitioned so that it will only be accessed by a single thread rather than being shared by all threads.
By default each thread receives its own stack. So if you allocate a variable on the stack then it will typically only be accessed by a single thread. Note that it is possible to pass a pointer to a stack variable from one thread to another, but this is not recommended and could be the source of the sort of problems that you are seeing.
Another way for a thread to receive its own copy of a variable is using thread local storage. This allows each thread to have its own copy of a global variable.
In summary, although threads share an address space they can work on private data. But you need to be careful with how you are sharing data between threads and avoid data races.