使用全局变量的线程问题

若昂

我正在研究 Linux 和操作系统中使用的线程。我正在做一些运动。目标是对一个全局变量的值求和,最后查看结果。当我看到最后的结果时,我的心就炸了。代码如下

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>

int i = 5;

void *sum(int *info);

void *sum(int *info)
{
    //int *calc = info (what happened?)
    int calc = info;

    i = i + calc;

    return NULL;
}

int main()
{
    int rc = 0,status;
    int x = 5;

    pthread_t thread;

    pthread_t tid;
    pthread_attr_t attr;

    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

    rc = pthread_create(&thread, &attr, &sum, (void*)x);
    if (rc) 
    {              
        printf("ERROR; return code from pthread_create() is %d\n", rc);
        exit(-1);
    }

    rc = pthread_join(thread, (void **) &status);
    if (rc) 
    {
        printf("ERROR; return code from pthread_join() is %d\n", rc);
        exit(-1);
    }

    printf("FINAL:\nValue of i = %d\n",i);
    pthread_attr_destroy(&attr);
    pthread_exit(NULL);

    return 0;
}

如果我将变量 calc 作为 int *cal 放在 sum 函数中,那么 i 的最终值是 25(不是预期值)。但是如果我把它作为 int calc 那么我的最终值是 10(我在这个练习中的期望值)。我不明白当我将变量 calc 设为 int *calc 时,i 的值怎么会是 25。

巴西尔·斯塔林克维奇

阅读一些关于 pthreads 的教程在多个线程中访问和修改全局数据时,您不能期望可重现的行为(没有与同步相关的额外编码预防措施)。AFAIU 您的代码表现出一些棘手的未定义行为,您应该感到害怕(也许在您的情况下这只是未指定的行为)。要解释观察到的具体行为,您需要深入研究实现细节(而您没有时间这样做:研究生成的汇编代码、特定硬件的行为等……)。

另外(因为info指向an指针int

int calc = info;

没有多大意义(我猜你打错了)。在某些系统上(比如我的 x86-64 运行 Linux),指针比 an 宽int(因此从 中calc丢失了一半的位info)。在其他(稀有)系统上,它的尺寸可能更小。有时(运行 Linux 的 i686)它可能具有相同的大小。您应该考虑intptr_tfrom<stdint.h>是否要将指针转换为整数值并返回。

实际上,您应该使用mutex保护对全局数据(内部i,可能通过指针访问)的访问,或者在 C11原子操作中使用,因为该数据由多个并发线程使用。

所以你可以声明一个全局互斥锁

 pthread_mutext_t mtx = PTHREAD_MUTEX_INITIALIZER;

(或使用pthread_mutex_init)然后在你的sum代码中

pthread_mutex_lock(&mtx);
i = i + calc;
pthread_mutex_unlock(&mtx);

(另见pthread_mutex_lockpthread_mutex_lock(3p))。当然你也应该在你的main.

锁定互斥锁有点昂贵(通常是添加的几十倍),即使在它被解锁的情况下也是如此。如果您可以在 C11 中编码,您可能会考虑原子操作,因为您处理整数。您将声明atomic_int i;在其上使用atomic_loadatomic_fetch_add

如果您好奇,另请参阅pthreads(7)futex(7)

多线程编程真的很难(对所有人来说)。您不能期望行为在一般情况下是可重现的,并且您的代码显然可以按预期运行但仍然非常错误(并且在某些不同的系统上会以不同的方式工作)。另请阅读有关内存模型CPU 缓存缓存一致性并发计算...

考虑使用 GCC 线程消毒工具选项和/或valgrindhelgrind

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

Python线程全局变量问题

来自分类Dev

使用线程打印全局变量

来自分类Dev

使用全局变量的WebSocket线程

来自分类Dev

全局变量问题

来自分类Dev

全局变量问题

来自分类Dev

全局变量使用

来自分类Dev

使用多线程时保护全局变量

来自分类Dev

Python的全局变量问题

来自分类Dev

C# 使用全局变量时遇到问题

来自分类Dev

不同函数的全局变量问题(使用 Python)

来自分类Dev

python线程:事件与全局变量

来自分类Dev

用线程增加全局变量

来自分类Dev

用线程增加全局变量

来自分类Dev

Sidekiq线程访问全局变量

来自分类Dev

使用PHP全局变量

来自分类Dev

何时使用全局变量

来自分类Dev

Tkinter Python的全局变量问题

来自分类Dev

全局变量和for循环的奇怪问题

来自分类Dev

标头和全局变量问题

来自分类Dev

全局变量和Alamofire的问题

来自分类Dev

Python中的全局变量问题

来自分类Dev

Tkinter Python的全局变量问题

来自分类Dev

JavaScript问题中的全局变量

来自分类Dev

全局变量的JavaScript作用域问题

来自分类Dev

全局变量设置出现问题

来自分类Dev

使用线程安全针对局部变量和全局变量进行Java垃圾收集

来自分类Dev

Tcl线程:如何访问线程中的全局变量

来自分类Dev

线程访问全局变量并强制杀死旧线程

来自分类Dev

如何使用全局变量的值来确定在单独线程中运行的函数的控制流?