在C中不同线程之间访问变量时,变量的行为如何?

euoag5mw  于 2023-11-17  发布在  其他
关注(0)|答案(2)|浏览(125)

假设我有两个并行运行的线程,其中一个保持一个x元素的静态数组,它每100毫秒不断更新。另一个线程可以访问一个'IsIn'函数,如果某个元素存在于所述数组中,则返回1。
我的问题是,当调用IsIn函数时,是否存在这样的风险,即数组同时被update函数更新,并且可能给予错误的结果?分配给该数组的内存的管理实际上是如何工作的?有没有方法可以防止这个问题?

mxg2im7a

mxg2im7a1#

我想.通过IsIn函数或甚至一个简单的Get函数从线程2访问线程1中的数组,以一种方式,我可以确保在线程2中调用这些函数之一时,数组.没有在调用中被更新和更改,这可能会导致一些[un]想要的结果。

不想要的结果

在C语言中,唯一可能的“不想要的结果”就是你不想要的结果。对于C语言的运行时来说,数组只是一块内存,运行时根本不关心你对它做了什么。
我们大多数人都不想要的“结果”是数组中的数据存在某种 * 结构 *,使得一些可能的配置是“有效”的,而其他配置是“无效”的。线程通常不可能将数据从一种有效状态更改为另一种状态,而不暂时将其置于无效状态。
在这种情况下,基本的补救措施是使用mutex来保护数据。互斥体做两件事:
1.它有两种状态:“locked”和“unlocked”,它从不允许多个线程同时锁定互斥体,
1.也就是说,lockunlock动作定义了可以在线程之间进行比较的时刻。

同步

Synchronization是一个大交易。你问,
当调用IsIn函数时,是否存在更新函数 * 同时 * 更新数组并可能给予错误结果的风险?
如果事件A发生在线程1中,事件B发生在线程2中,而两个线程之间没有同步,那么对于“哪个事件先发生”这个问题没有有意义的答案。“但是,如果线程1在锁定了某个互斥体时只导致事件A,而线程2在锁定了同一个互斥体时只导致事件B,那么我们就知道这些事件不可能同时发生。2然后我们就可以推理或编写代码来证明哪一个事件先发生。

使用Mutex

因此,如果线程1更新了结构化数据,并且我们希望确保线程2永远不会看到处于无效状态的数据,我们这样做:

#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试图在线程1已经锁定互斥体的情况下锁定互斥体,那么线程2中的pthread_mutex_lock()调用将不会返回,直到线程1解锁互斥体。

谁先走

我的例子 * 并不 * 阻止线程2在 * 线程1更新之前获取互斥量 *。互斥量,当以这种方式使用时,只保证线程2将看到有效数据。但是线程2可以看到新的有效状态,或者旧的有效状态。你不能使用互斥量来控制线程做事情的顺序。
如果你需要线程“会合”、“轮流”、“等待对方”,或者以任何其他方式来控制它们做事情的顺序,那就是更高级别的同步,这应该是另一个问题的主题。

  • 在一些编程语言(例如Java)中,“数组”是一种结构化对象,可以在运行时增长,或者被垃圾收集器移动。在这些语言中,即使你不关心数组中的内容,如果线程在没有足够同步的情况下访问它,你仍然可以扰乱运行时系统。

†这个网站上有很多新手的问题,他们 * 认为 * 他们可以使用互斥锁来控制线程之间的某些操作序列。有时候,这看起来很诱人,但它从来没有成功过。

yhxst69z

yhxst69z2#

我的问题是,在调用IsIn函数时,是否存在更新函数同时更新数组并可能给予错误结果的风险?
是的
如何管理分配给该阵列的内存?。
假设static,它被分配一次并放置在.bss/.data段中。它将在调用main之前初始化,即在执行线程回调之前很久。
如果多个线程同时访问数组的同一部分,则会出现争用条件错误。
有没有办法防止这个问题?
这里可以使用C语言的一个奇怪的特性,即存储类说明符_Thread_local。这意味着声明为_Thread_local int arr[] = ...的数组只在给定的线程内有效,并且只在该线程执行期间有效。如果线程回调结束,则数组变为无效。
另一种选择是在调用方声明数组,然后将指向数组的指针传递给每个线程,以及每个线程应该访问的数组部分的指令,确保它们不会与数组的重叠区域一起工作。这就是OpenMP等库为您做的-在主线程中创建循环的并行执行。
最后一个可选的是保护/同步机制:线程之间共享的信号量、互斥体、临界区等。

相关问题