gpt4 book ai didi

c - 使用 uint32_t 和 GCC 原子指令 union 32 位结构

转载 作者:太空宇宙 更新时间:2023-11-04 03:44:06 25 4
gpt4 key购买 nike

在编写的多线程程序中,我遇到了一些锁争用非常高的性能问题。

我通过在 32 位无符号整数中添加一些标志解决了这个问题。

目前我只是将值移位到一个临时变量中,然后自动写入它。

但我真的不想记住位移的确切数量或标志所在的确切位置。

所以我一直在想,我是否可以与 uint32_t 和具有相同大小的位标志的结构建立 union ,难道我不能通过结构访问位标志并自动将其写为 uint32_t 吗?

下面是我希望它如何工作的代码。它确实有效,但我不确定是否允许这样做

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>

typedef struct atomic_flags {
unsigned int flags1 : 2;
unsigned int flags2 : 2;
unsigned int flags3 : 2;
unsigned int flags4 : 2;
unsigned int flags5 : 8;
unsigned int reserved : 16;
}atomic_flags;

union data {
atomic_flags i;
uint32_t q;
} data;



int main() {
union data test1;
union data test2;

test1.i.flags1 = 1;
test1.i.flags2 = 2;
test1.i.flags3 = 3;
test1.i.flags4 = 2;
test1.i.flags5 = 241;
test1.i.reserved = 1337;

printf("%u\n", test1.q);

__atomic_store_n(&test2.q, test1.q, __ATOMIC_SEQ_CST);

printf("test1 flags1: %u\n", test1.i.flags1);
printf("test1 flags2: %u\n", test1.i.flags2);
printf("test1 flags3: %u\n", test1.i.flags3);
printf("test1 flags4: %u\n", test1.i.flags4);
printf("test1 flags5: %u\n", test1.i.flags5);
printf("test1 reserved: %u\n", test1.i.reserved);

printf("test2 flags1: %u\n", test2.i.flags1);
printf("test2 flags2: %u\n", test2.i.flags2);
printf("test2 flags3: %u\n", test2.i.flags3);
printf("test2 flags4: %u\n", test2.i.flags4);
printf("test2 flags5: %u\n", test2.i.flags5);
printf("test2 reserved: %u\n", test2.i.reserved);

}

或者这甚至是可能的?

__atomic_store_n(&test2.i.flags1, 2, __ATOMIC_SEQ_CST);

最佳答案

它是实现定义的。

如果你想让所有的掩蔽和移动更容易并减少出错的可能性,那么一个更坚固(但更丑陋)的方法是让预处理器帮助你:

/*
* widths of the bitfields; these values can be changed independently of anything
* else, provided that the total number of bits does not exceed 32.
*/
#define FLAG_flag1_BITS 2
#define FLAG_flag2_BITS 2
#define FLAG_flag3_BITS 2
#define FLAG_flag4_BITS 2
#define FLAG_flag5_BITS 8
/* Macro evaluating to the number of bits in the named flag */
#define FLAG_BITS(flagname) (FLAG_ ## flagname ## _BITS)

/*
* Positions of the flags in the overall bitmask; these adapt to the flag widths
* above, but a new macro (with the same pattern) will be needed if a bitfield
* is added.
*/
#define FLAG_flag1_SHIFT 0
#define FLAG_flag2_SHIFT (FLAG_flag1_SHIFT + FLAG_flag1_BITS)
#define FLAG_flag3_SHIFT (FLAG_flag2_SHIFT + FLAG_flag2_BITS)
#define FLAG_flag4_SHIFT (FLAG_flag3_SHIFT + FLAG_flag3_BITS)
#define FLAG_flag5_SHIFT (FLAG_flag4_SHIFT + FLAG_flag4_BITS)
/* Macro evaluating to the position of the named flag in the overall bitfield */
#define FLAG_SHIFT(flagname) (FLAG_ ## flagname ## _SHIFT)

/* evaluates to a bitmask for selecting the named flag's bits from a bitfield */
#define FLAG_MASK(flagname) \
((~(((uint32_t) 0xffffffff) << FLAG_BITS(flagname))) << FLAG_SHIFT(flagname))
/* evaluates to a bitfield having the specified flag set to the specified value */
#define FLAG(flagname, v) ((v << FLAG_SHIFT(flagname)) & FLAG_MASK(flagname))

/* macro to set the specified flag in the specified bitfield to the specified value */
#define SET_FLAG(flagname, i, v) \
do { i = (i & ~FLAG_MASK(flagname)) | FLAG(flagname, v); } while (0)
/* macro to retrieve the value of the specified flag from the specified bitfield */
#define GET_FLAG(flagname, i) (((i) & FLAG_MASK(flagname)) >> FLAG_SHIFT(flagname))

/* usage example */
int function(uint32_t bitfield) {
uint32_t v;

SET_FLAG(flag2, bitfield, 1);
v = GET_FLAG(flag5, bitfield);
}

虽然这涉及大量的宏,但它主要是由第一组驱动的,它给出了位域宽度。基本上所有这些都将编译为您无论如何都会使用的相同移位和掩码操作,因为计算将主要由预处理器和/或编译器执行。实际使用非常简单。

关于c - 使用 uint32_t 和 GCC 原子指令 union 32 位结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26281707/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com