互斥锁在解锁之前是否会阻止访问?
Does a mutex lock prevent access until it's unlocked?
假设这个 C 代码:
#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);
}
第一个输出是5
,但随后的输出都是6
。那个怎么样?
myThreadFun
创建一个锁并进入无限循环并且永远不会解锁,那么 main
如何覆盖 a
?
放在lock
之间的任何东西都会受到保护?也就是说,如果我在 myThreadFun
中有更多变量要保护,我只是将它们放在同一个锁之间?
锁是在解锁之前阻止访问,还是只在自己的 read/write 完成之前阻止访问?即防止部分读写?
myThreadFun
creates a lock and goes in an infinite loop and never unlocks
是的,但是那把锁是用来做什么的?没有什么。除了线程,没有其他人在使用锁。 main
程序在不请求任何锁的情况下访问变量。该程序不知道锁应该保护 a
变量这一事实。它真的可以用于任何事情。锁只能防止代码的关键区域被多个线程同时执行,因为所有线程都在关键区域的开头锁定并在结尾解锁。
如果您希望它正确运行,则必须正确使用锁,并且 lock/release 它适用于与变量交互的代码的每个部分。像这样(在 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?
锁对read/write、代码或变量一无所知。锁只是一个具有两种状态的对象:锁定或解锁。如果它的状态是解锁的,那么它就可以被锁定。如果它的状态是锁定的,那么在解锁发生之前它不能被锁定(并且请求锁导致线程等待直到锁被解锁)。
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.
这是一个不同的问题。您在这里需要做的是确保您启动的线程在主线程之前可以访问a
变量。如果要实现此结果,则需要使两者同步。换句话说,您希望 main
程序等待直到线程持有变量的锁。
这可以通过不同的方式实现。这是一个使用信号量的工作示例(查看 man sem_overview
了解更多信息)。 注意 虽然使用另一个互斥量而不是信号量似乎可以实现以下内容,但事实并非如此。互斥量和信号量之间的主要区别在于,互斥量只能由锁定它的同一个线程解锁,而信号量可以由不同的线程自由地锁定或解锁。
#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);
}
在上面的例子程序中main
会等待线程获取锁之后再继续。结果输出将是:
Thread: a = 5
Thread: a = 5
Thread: a = 5
...
如果您希望某个变量只能访问特定线程,请在内部线程函数中声明它:
void *myThreadFun(void *unused)
{
int a = 5;
while (1) sleep(1);
return 0;
}
现在main
根本搞不定,加锁也没用
假设这个 C 代码:
#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);
}
第一个输出是5
,但随后的输出都是6
。那个怎么样?
myThreadFun
创建一个锁并进入无限循环并且永远不会解锁,那么 main
如何覆盖 a
?
放在lock
之间的任何东西都会受到保护?也就是说,如果我在 myThreadFun
中有更多变量要保护,我只是将它们放在同一个锁之间?
锁是在解锁之前阻止访问,还是只在自己的 read/write 完成之前阻止访问?即防止部分读写?
myThreadFun
creates a lock and goes in an infinite loop and never unlocks
是的,但是那把锁是用来做什么的?没有什么。除了线程,没有其他人在使用锁。 main
程序在不请求任何锁的情况下访问变量。该程序不知道锁应该保护 a
变量这一事实。它真的可以用于任何事情。锁只能防止代码的关键区域被多个线程同时执行,因为所有线程都在关键区域的开头锁定并在结尾解锁。
如果您希望它正确运行,则必须正确使用锁,并且 lock/release 它适用于与变量交互的代码的每个部分。像这样(在 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?
锁对read/write、代码或变量一无所知。锁只是一个具有两种状态的对象:锁定或解锁。如果它的状态是解锁的,那么它就可以被锁定。如果它的状态是锁定的,那么在解锁发生之前它不能被锁定(并且请求锁导致线程等待直到锁被解锁)。
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.
这是一个不同的问题。您在这里需要做的是确保您启动的线程在主线程之前可以访问a
变量。如果要实现此结果,则需要使两者同步。换句话说,您希望 main
程序等待直到线程持有变量的锁。
这可以通过不同的方式实现。这是一个使用信号量的工作示例(查看 man sem_overview
了解更多信息)。 注意 虽然使用另一个互斥量而不是信号量似乎可以实现以下内容,但事实并非如此。互斥量和信号量之间的主要区别在于,互斥量只能由锁定它的同一个线程解锁,而信号量可以由不同的线程自由地锁定或解锁。
#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);
}
在上面的例子程序中main
会等待线程获取锁之后再继续。结果输出将是:
Thread: a = 5
Thread: a = 5
Thread: a = 5
...
如果您希望某个变量只能访问特定线程,请在内部线程函数中声明它:
void *myThreadFun(void *unused)
{
int a = 5;
while (1) sleep(1);
return 0;
}
现在main
根本搞不定,加锁也没用