Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在C语言中使用原子变量?_C_Linux_Atomic - Fatal编程技术网

如何在C语言中使用原子变量?

如何在C语言中使用原子变量?,c,linux,atomic,C,Linux,Atomic,我需要在C中使用一个原子变量,因为这个变量是跨不同线程访问的。我不想要比赛条件 我的代码正在CentOS上运行。我的选项是什么?如果您在CentOS平台上使用GCC,则可以使用 特别令人感兴趣的可能是这一职能: -内置函数:bool\uu原子\u始终\u锁定\u自由(大小\u t大小,无效*ptr) 如果大小字节的对象总是为目标体系结构生成无锁原子指令,则此内置函数返回true大小必须解析为编译时常量,并且结果也解析为编译时常量。 ptr是指向可用于确定对齐的对象的可选指针。值0表示应使用典型对

我需要在C中使用一个原子变量,因为这个变量是跨不同线程访问的。我不想要比赛条件


我的代码正在CentOS上运行。我的选项是什么?

如果您在CentOS平台上使用GCC,则可以使用

特别令人感兴趣的可能是这一职能:

-内置函数:
bool\uu原子\u始终\u锁定\u自由(大小\u t大小,无效*ptr)

如果
大小
字节的对象总是为目标体系结构生成无锁原子指令,则此内置函数返回true<代码>大小必须解析为编译时常量,并且结果也解析为编译时常量。
ptr
是指向可用于确定对齐的对象的可选指针。值
0
表示应使用典型对齐方式。编译器也可以忽略此参数

      if (_atomic_always_lock_free (sizeof (long long), 0))

C11原子原语

在glibc 2.28中添加。通过从源代码编译glibc在Ubuntu 18.04(glibc 2.27)中进行了测试:后来也在Ubuntu 20.04、glibc 2.31上进行了测试

示例改编自:

main.c

#include <stdio.h>
#include <threads.h>
#include <stdatomic.h>

atomic_int acnt;
int cnt;

int f(void* thr_data)
{
    (void)thr_data;
    for(int n = 0; n < 1000; ++n) {
        ++cnt;
        ++acnt;
        // for this example, relaxed memory order is sufficient, e.g.
        // atomic_fetch_add_explicit(&acnt, 1, memory_order_relaxed);
    }
    return 0;
}

int main(void)
{
    thrd_t thr[10];
    for(int n = 0; n < 10; ++n)
        thrd_create(&thr[n], f, NULL);
    for(int n = 0; n < 10; ++n)
        thrd_join(thr[n], NULL);

    printf("The atomic counter is %u\n", acnt);
    printf("The non-atomic counter is %u\n", cnt);
}
可能的产出:

The atomic counter is 10000
The non-atomic counter is 8644
由于线程间对非原子变量的快速访问,非原子计数器很可能比原子计数器小


拆卸分析在:

我将投入我的两分钱,以防有人受益。原子操作是Linux中的一个主要问题。我曾经用过gatomic.h,结果发现它不见了。我看到了各种不同的原子选项,无论是可靠性还是可用性都值得怀疑——我看到事情一直在变化。它们可能会因O/S级、处理器等所需的测试而变得复杂。您可以使用互斥锁——不仅是非常慢的复杂互斥锁

虽然在线程中可能并不理想,但这对于共享内存变量的原子操作非常有效。它很简单,可以在每个O/S和处理器上工作,并且男人(或女人)都知道它的配置,非常可靠,易于编码,并且可以一直工作

任何代码都可以用一个简单的原语——一个信号量来实现原子化。它是真/假、1/0、是/否、锁定/解锁——二进制

建立信号量后:

set semaphore   //must be atomic
result = lockf(ablockfd, F_ULOCK, 1);   //after same lseek
执行您喜欢的所有代码,这些代码将是原子的,因为信号量将为您阻塞

release semaphore  //must be atomic
除“必须是原子的”行外,其他行相对简单

事实证明,您可以轻松地为信号量分配一个数字(我使用define,因此它们的名称类似于“#define OPEN_SEM 1”和“#define”CLASS_SEM 2”,等等)

找出您的最大数字,并在程序初始化时在某个目录中打开一个文件(我使用一个仅用于此目的)。如果没有,请创建它:

if (ablockfd < 0) {         //ablockfd is static in case you want to 
                            //call it over and over           
    char *get_sy_path();                
    char lockname[100];                 

    strcpy(lockname, get_sy_path());    
    strcat(lockname, "/metlock");       
    ablockfd = open(lockname, O_RDWR);
    //error code if ablockfd bad
}
要测试信号量是否保持不变,请执行以下操作:

result = lockf(ablockfd, F_TEST, 1);  //after same lseek
要释放信号量,请执行以下操作:

set semaphore   //must be atomic
result = lockf(ablockfd, F_ULOCK, 1);   //after same lseek
还有你可以用lockf做的所有其他事情——阻塞/非阻塞,等等


注意——这比互斥锁快得多,如果进程死掉它就会消失(这是件好事),代码简单,而且我知道没有任何操作系统的处理器有任意数量的互斥锁,或者内核数量不能自动锁定记录……所以简单的代码可以正常工作。文件永远不存在(没有字节,但在目录中),似乎对您可能拥有的数量没有实际限制。我已经在没有简单原子解决方案的机器上使用了多年。

此外,这可能值得一读:看起来CentOS的pthreads是可用的,因此您可以使用互斥来同步访问。类型
volatile sig_atomic_t
保证具有原子访问ss@RickyMutschlechner:
volatile
不能做到这一点。请参考你链接到的维基百科文章:“对volatile变量的操作不是原子的……”RickyMutschlechner:你不能仅仅使用
volatile
实现自旋锁,因为即使编译器没有,处理器也会重新排序IO。问题还说“不想要竞争条件”,如果您担心竞争条件,那么
volatile
就不是合适的工作工具。
result = lockf(ablockfd, F_ULOCK, 1);   //after same lseek