Based on my understanding, if I have a global variable and two or more threads that are trying to access it, and each thread is running on a different CPU core, then each CPU core will cache a copy of the global variable and whenever a thread tries to access the global variable, it is the cached copy that will be accessed, and not the global variable in memory.
Now say that I have two threads created using CreateThread() and each thread is running on a different CPU core, and one thread sets a global variable's value while the other thread reads its value.
Is there an Assembly instruction that forces the cached copy of the global variable to be flushed to memory after setting its value, or an Assembly instruction that updates the cached copy of the other CPU core that the other thread is running on?
Related
If the process contains only 1 thread. And in the code we define a variable int x = 10, it's not qualified by volatile.
first, thread runs on cpu core1, it read x and change it to 5;
then, thread sleep and re-scheduled onto another cpu core2;
then, thread try to read x from memory;
I have several questions:
Q1: cpu contains store buffer, and thread task_struct contains register values, so even though the store buffer not flushed to cache, the thread still will read the latest value by restoring the task context?
Q2: If the cpu register is reused by other instructions following changing x to 5, latest value 5 isn't stored in register now. Now switching happens, thread runs on another core2 now, will the thread read the latest value? Because the store buffer isn't flushed, cpu core2 won't see the cacheline invalidated, I think the thread will read from memory, so read value is 10? Or the OS apply some barriers for flushing out the entire store buffer before context switching and invalidating the invalidate queue before reading?
i created a shared mutex and conditional variable on shared memory for communication between two process (producer and consumer) , if i close both application , and run again , i can lock , unlock mutex and signal conditional variable without recreate them on shared memory again , mutex and cond variable are working good without recreate them , how is this possible ? making shared a mutex and cond variable , makes them lifetime until restart machine ? Note : if i press ctrl + c and interrupt consumer and restart again both application locked and i need to delete /dev/shm/ipcfile .
Whether a mutex is locked or unlocked depends on the values that are stored in the memory corresponding to it. Shared memory persists until you delete it and it is no longer used, so if you create a shared memory area with a mutex in it and lock it, it will remain locked. If the mutex is unlocked, it will still have been initialized, since the shared memory segment persists.
If you want to consistently produce an environment where your mutex is unlocked on startup, use POSIX shared memory with O_TRUNC in the producer and then call ftruncate and mmap to allocate your memory, and then initialize the mutex. The consumer (or multiple consumers) can then lock the mutex and unlock the mutex, knowing it's been created. Since the producer truncates the memory, any old mutex state there will be destroyed.
It's also possible to do this with SysV shared memory, but a little less elegant. You would just remove the segment to be destroyed with shmctl using IPC_RMID in the producer, ignoring any errors, and then create a new shared memory segment. Then you can initialize the mutex in the memory area.
I want to use 3 threads in my qt project,while using a global pointer array variable,3 threads will not change it`s value
If you can guarantee that the contents of the global variable will never change during the time it is accessible to multiple threads, then it is safe for the threads to read that global variable without doing any synchronization.
I have a delphi7 program with two threads. If I alloc memory in the first thread using new(), can I release it with dispose in the other thread ? I also am using fastMM
Yes. Dynamic memory is shared between all threads in the process.
You must make sure that the IsMultiThread global variable is set True at an early stage. Using TThread or BeginThread to create threads will set IsMultiThread to True. If you know that your code uses threads then you may as well set IsMultiThread to True explicitly during initialization.
Obviously the allocation must complete before you start the deallocation.
Yes, all memory of the current process is accessible to all threads. But you should absolutely make sure that these calls are not made simultaneously or do not take place in the wrong order, because that is easily done with multiple threads whose execution time is unpredictable.
mprotect() is used to protect memory pages, for example, making pages read-only. It sets this protection for the whole process, that is, if a page is read-only, no thread can write to that page. Is there a way to protect pages in different ways for different threads? For example, 1 thread can write to page P, and all other threads in my program can only read from P.
If you create a thread using CLONE_VM flag in the "clone" system call (this is what you would normally call a thread) then the MMU settings are the same as for the parent thread.
This means that write access is possible for both threads.
If you do not use CLONE_VM flags then the both threads do not have shared memory at all!
(pthread_create() sets the CLONE_VM flag internally).
It would be possible to do what you want - however it would be very difficult:
Allocate all memory blocks using shared memory functions (e.g. shmget()) instead of standard functions (e.g. malloc()).
If a new thread is created use "clone()" directly instead of "pthread_create()" with the CLONE_VM flag not set.
The shared memory is shared between the threads and the threads created by "normal" memory allocation functions (e.g. malloc()) is not shared between the threads. The same is true for mmap() mapped memory.
When a new thread is created such memory blocks (created by malloc or mmap) are copied so that both threads have their own copy of this memory block at the same address. If one thread writes to this address then the other thread will not see the change.
Allocating more "shared" memory is rather tricky. It is easy if the memory only should be shared between the allocating thread and child threads that are not created, yet. it is difficult to share memory between already-running threads or between threads that are (indirect) children of different already-running threads.
The threads do not have shared stack memory so they cannot access each other's stack.
Global and "static" variables are not shared by default - to make them "shared" between the threads some tricky programming is required.
With newer Intel CPUs you can use Memory Protection Keys [1] for different access settings per thread within a process. On Linux, run lscpu and check for the pku and ospke flags.
The example on the man page [2] is a bit outdated in the sense that the corresponding system calls do not need to be invoked manually anymore. Instead, glibc provides the following API calls:
pkey_alloc() to allocate a new key (16 are available)
pkey_set() to set the permission for a given key
pkey_mprotect() to apply the key to a given memory region
pkey_free() to free a key
Since the register that maintains the permission bits per protection key is thread-local, different protection settings are possible per thread. Protection key settings can only further lock down the general settings and do not affect instruction fetch.
[1] https://www.kernel.org/doc/Documentation/x86/protection-keys.txt
[2] http://man7.org/linux/man-pages/man7/pkeys.7.html