#include <pthread.h>
pthread_mutex_t mutex;
// During program startup, before creating the threads;
if (pthread_mutex_init(&mutex, NULL) != 0) {
fprintf(stderr, "\n mutex init failed\n");
exit(1);
}
// In thread 1;
pthread_mutex_lock(&mutex);
...update the shared data...
...Don't forget to always leave the data in a valid state...
pthread_mutex_unlock(&mutex);
// In thread 2;
pthread_mutex_lock(&mutex);
...use the shared data, confident that it *must* be valid...
pthread_mutex_unlock(&mutex);
2条答案
按热度按时间mxg2im7a1#
我想.通过
IsIn
函数或甚至一个简单的Get
函数从线程2访问线程1中的数组,以一种方式,我可以确保在线程2中调用这些函数之一时,数组.没有在调用中被更新和更改,这可能会导致一些[un]想要的结果。不想要的结果
在C语言中,唯一可能的“不想要的结果”就是你不想要的结果。对于C语言的运行时来说,数组只是一块内存,运行时根本不关心你对它做了什么。
我们大多数人都不想要的“结果”是数组中的数据存在某种 * 结构 *,使得一些可能的配置是“有效”的,而其他配置是“无效”的。线程通常不可能将数据从一种有效状态更改为另一种状态,而不暂时将其置于无效状态。
在这种情况下,基本的补救措施是使用mutex来保护数据。互斥体做两件事:
1.它有两种状态:“locked”和“unlocked”,它从不允许多个线程同时锁定互斥体,
1.也就是说,
lock
和unlock
动作定义了可以在线程之间进行比较的时刻。同步
Synchronization是一个大交易。你问,
当调用IsIn函数时,是否存在更新函数 * 同时 * 更新数组并可能给予错误结果的风险?
如果事件A发生在线程1中,事件B发生在线程2中,而两个线程之间没有同步,那么对于“哪个事件先发生”这个问题没有有意义的答案。“但是,如果线程1在锁定了某个互斥体时只导致事件A,而线程2在锁定了同一个互斥体时只导致事件B,那么我们就知道这些事件不可能同时发生。2然后我们就可以推理或编写代码来证明哪一个事件先发生。
使用Mutex
因此,如果线程1更新了结构化数据,并且我们希望确保线程2永远不会看到处于无效状态的数据,我们这样做:
字符串
如果线程2试图在线程1已经锁定互斥体的情况下锁定互斥体,那么线程2中的
pthread_mutex_lock()
调用将不会返回,直到线程1解锁互斥体。谁先走
我的例子 * 并不 * 阻止线程2在 * 线程1更新之前获取互斥量 *。互斥量,当以这种方式使用时,只保证线程2将看到有效数据。但是线程2可以看到新的有效状态,或者旧的有效状态。你不能使用互斥量来控制线程做事情的顺序。
如果你需要线程“会合”、“轮流”、“等待对方”,或者以任何其他方式来控制它们做事情的顺序,那就是更高级别的同步,这应该是另一个问题的主题。
†这个网站上有很多新手的问题,他们 * 认为 * 他们可以使用互斥锁来控制线程之间的某些操作序列。有时候,这看起来很诱人,但它从来没有成功过。
yhxst69z2#
我的问题是,在调用IsIn函数时,是否存在更新函数同时更新数组并可能给予错误结果的风险?
是的
如何管理分配给该阵列的内存?。
假设
static
,它被分配一次并放置在.bss
/.data
段中。它将在调用main之前初始化,即在执行线程回调之前很久。如果多个线程同时访问数组的同一部分,则会出现争用条件错误。
有没有办法防止这个问题?
这里可以使用C语言的一个奇怪的特性,即存储类说明符
_Thread_local
。这意味着声明为_Thread_local int arr[] = ...
的数组只在给定的线程内有效,并且只在该线程执行期间有效。如果线程回调结束,则数组变为无效。另一种选择是在调用方声明数组,然后将指向数组的指针传递给每个线程,以及每个线程应该访问的数组部分的指令,确保它们不会与数组的重叠区域一起工作。这就是OpenMP等库为您做的-在主线程中创建循环的并行执行。
最后一个可选的是保护/同步机制:线程之间共享的信号量、互斥体、临界区等。