I need some help for understanding general basics of shared resource access in C++ multithreading.
When I need some variable that must be accessible for several threads, I declare it as atomic, or synchronize operations with it by mutex.
But what if some function/method required pointer to type, and I must protect my variable(shared resource) for read/write in multiply threads. I know that in C and C++ pointers is passed by value, but anyway that confused me.
Question. Can I need to lock pointer to shared resource too:
void foo (int * pi = nullptr)
{
//{..} some ops
static std::mutex mtx;
std::unique_lock<std::mutex> lock(mtx); // lock mutex BEFORE ptr check
if(pi){
++(*pi); // dereference ptr's shared resource
}
lock.unlock();
//{...} some ops
}
OR lock only for resource itself:
void foo (int * pi = nullptr)
{
//{..} some ops
static std::mutex mtx;
if(pi){ // check if ptr is not null, is this thread-safe ?
std::unique_lock<std::mutex> lock(mtx); // lock mutex ONLY for access shared resource itself,
// not for pointer that refers to it
++(*pi); // dereference ptr's shared resource
lock.unlock();
}
//{...} some ops
}
Here some dumb "synthetic" example call with shared resource:
int main(){
int __i = 0;
std::thread t([&__i](){
for(;;){
foo(&__i);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
});
for(;;){
foo(&__i);
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
//std::cout << __i << std::endl;
}
t.join();
}
P.S. 'int' type in this example only for clarity.
__(although I think that only those starting with_and a capital letter are strictly reserved).ints whose sum must always be zero. It is impossible for any thread to change any of those variables without temporarily "breaking" the invariant. Synchronization is how we prevent other threads from seeing the temporary, broken state.__anywhere in it is reserved, and declaring/defining such an identifier in one's code is undefined behavior. Your first inclination is correct.