C - 全局指针可以被不同的线程修改吗?

标签 c multithreading pointers

全局指针是否具有线程之间存在的范围?

例如,假设我有两个文件,file1.c 和 file2.c:

文件1.c:

uint64_t *g_ptr = NULL;

modify_ptr(&g_ptr) { 
    //code to modify g_ptr to point to a valid address 
}

read_from_addr() {
    //code which uses g_ptr to read values from the memory it's pointing to
}

文件2.c:

function2A() {
    read_from_addr();
}

所以我有 threadA,它通过 file1.c 运行并执行 modify_ptr(&g_ptr) 和 read_from_addr()。然后 threadB 运行,它运行通过 file2.c 执行 function2A()。

我的问题是:threadB 是否看到 g_ptr 被修改了?还是它仍然看到它指向 NULL?

如果不是这样,指针是全局的意味着什么?以及如何确保该指针可在不同线程之间访问?

如果我需要澄清任何事情,请告诉我。谢谢

最佳答案

My question is: Does threadB see that g_ptr is modified? Or does it still see that it's pointing to NULL?

也许吧。如果在没有任何外部同步的情况下访问,您可能会看到奇怪的、高度不可重现的结果——在某些情况下,编译器可能会根据其对代码的分析进行某些优化,这可能源于假设变量是在某些代码路径期间未修改。例如,考虑这段代码:

// Global variable
int global = 0;

// Thread 1 runs this code:
while (global == 0)
{
    // Do nothing
}

// Thread 2 at some point does this:
global = 1;

在这种情况下,编译器可以看到globalwhile循环内部没有被修改,也没有调用任何外部函数,因此可以“优化” "它变成这样的东西:

if (global == 0)
{
    while (1)
    {
        // Do nothing
    }
}

volatile 关键字添加到变量的声明中可防止编译器进行此优化,但这不是 volatile 的预期用例,因为 C 语言是标准化。在此处添加 volatile 只会稍微减慢您的程序并掩盖真正的问题——缺乏适当的同步。

管理需要从多个线程同时访问的全局变量的正确方法是使用互斥锁来保护它们1。例如,下面是使用 POSIX 线程互斥体的 modify_ptr 的简单实现:

uint64_t *g_ptr = NULL;
pthread_mutex_t g_ptr_mutex = PTHREAD_MUTEX_INITIALIZER;

void modify_ptr(uint64_t **ptr, pthread_mutex_t *mutex)
{
    // Lock the mutex, assign the pointer to a new value, then unlock the mutex
    pthread_mutex_lock(mutex);
    *ptr = ...;
    pthread_mutex_unlock(mutex);
}

void read_from_addr()
{
    modify_ptr(&g_ptr, &g_ptr_mutex);
}

互斥函数确保插入正确的内存屏障,因此对受互斥锁保护的变量所做的任何更改都将正确传播到其他 CPU 内核,前提是变量的每次访问(包括读取!)都受到互斥体。

1) 您也可以使用专门的无锁数据结构,但这是一种高级技术,很容易出错

关于C - 全局指针可以被不同的线程修改吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18599012/

相关文章:

c++ - 返回引用时,gcc 将 0x30 添加到 %eax

for 循环的 C 运行时错误

可以在 C 中将静态变量声明为 extern 吗?

java - RxJava 中 REAL 背压的最佳实现

Java、多线程和 Raspberry Pi

java - 无法停止线程

C++,从 ‘char’ 到 ‘const char*’ 的无效转换

c - 为什么这个程序的打印输出没有停在 0 位?

c++ - c++ 中的位图 - unsigned int 会完成这项工作吗?

c - 基本主菜单代码不起作用