Reputation:
Assume this C code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
pthread_mutex_t lock;
int a = 0;
void *myThreadFun(void *vargp)
{
pthread_mutex_lock(&lock);
a = 5;
while (1) sleep(1);
pthread_mutex_unlock(&lock);
return NULL;
}
int main()
{
pthread_mutex_init(&lock, NULL);
pthread_t thread_id;
pthread_create(&thread_id, NULL, myThreadFun, NULL);
while (1){
a = 6;
sleep(1);
printf("%d\n", a);
}
pthread_join(thread_id, NULL);
}
The first output is 5
but the subsequent prints are all 6
. How is that?
myThreadFun
creates a lock and goes in an infinite loop and never unlocks, so how can main
overwrite a
?
Whatever put between a lock
will be protected? i.e if I have more variables to protect in myThreadFun
I just put the between the same lock?
Does a lock block access until it's unlocked, or it block access only until its own read/write is done? i.e to prevent a partial read and write?
Upvotes: 1
Views: 586
Reputation: 69276
myThreadFun
creates a lock and goes in an infinite loop and never unlocks
True, but what is that lock used for? Nothing. Nobody else is honoring the lock except the thread. The main
program accesses the variable without requesting any lock. The program does not know anything about the fact that the lock is supposed to guard the a
variable. It could be used for anything really. A lock only prevents critical regions of code from being executed by multiple threads at the same time given that all of them are locking at the beginning of the critical region and unlocking at the end.
If you want this to behave correctly, you'll have to use the lock properly, and lock/release it for every part of code which interacts with the variable. Something like this (in main
):
while (1) {
pthread_mutex_lock(&lock);
a = 6;
sleep(1);
printf("%d\n", a);
pthread_mutex_unlock(&lock);
}
Does a lock block access until it's unlocked, or it block access only until its own read/write is done? i.e to prevent a partial read and write?
A lock doesn't know anything about read/write, code or variables. A lock is simply an object that has two states: either locked or unlocked. If its state is unlocked, then it can be locked. If its state is locked, then it cannot be locked until an unlock occurs (and requesting a lock causes the thread to wait until the lock gets unlocked).
This still prints 6. I want it to print 5. I want to lock
a
in a thread so no other thread can touch it.
This is a different issue. What you need to do here is to ensure that the thread you are starting gets access to the a
variable before the main thread. If you want to achieve this result, you'll need to synchronize the two. In other words, you want the main
program to wait until the thread holds the lock on the variable.
This can be achieved in different ways. Here's a working example using a semaphore (take a look at man sem_overview
for more information). NOTE that while it might seem like the following could be achieved using another mutex instead of a semaphore, this is not the case. The main difference between a mutex and a semaphore is that a mutex can only be unlocked by the same thread that locked it, while a semaphore can freely be locked or unlocked by different threads.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
sem_t sem_main;
pthread_mutex_t lock_var_a;
int a = 0;
void *myThreadFun(void *vargp)
{
pthread_mutex_lock(&lock_var_a);
// Signal main that I acquired the lock.
sem_post(&sem_main);
a = 5;
while (1) {
printf("Thread: a = %d\n", a);
sleep(1);
}
pthread_mutex_unlock(&lock_var_a);
return NULL;
}
int main()
{
sem_init(&sem_main, 0, 0);
pthread_mutex_init(&lock_var_a, NULL);
pthread_t thread_id;
pthread_create(&thread_id, NULL, myThreadFun, NULL);
// Wait for thread to acquire the lock.
sem_wait(&sem_main);
while (1){
pthread_mutex_lock(&lock_var_a);
// This code will never be executed.
a = 6;
printf("Main: a = %d\n", a);
sleep(1);
pthread_mutex_unlock(&lock_var_a);
}
pthread_join(thread_id, NULL);
}
In the above example program main
will wait for the thread to acquire the lock before continuing. The resulting output will be:
Thread: a = 5
Thread: a = 5
Thread: a = 5
...
Upvotes: 4
Reputation: 140505
If you want a variable to be accessible only to a particular thread, declare it inside the thread function:
void *myThreadFun(void *unused)
{
int a = 5;
while (1) sleep(1);
return 0;
}
Now main
can't get at it at all, and locking is unnecessary.
Upvotes: 0