[英]How to modify structure elements atomically without using locks in C?
我想原子地修改结构的某些元素。 我当前的实现使用互斥锁来保护关键代码,如下所示。
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <pthread.h>
pthread_mutex_t thread_mutex = PTHREAD_MUTEX_INITIALIZER;
#define ITER 100000
typedef struct global_status {
int32_t context_delta;
uint32_t global_access_count;
} global_status_t;
global_status_t g_status;
void *context0(void *ptr)
{
unsigned int iter = ITER;
while (iter--) {
wait_event_from_device0();
pthread_mutex_lock(&thread_mutex);
g_status.context_delta++;
g_status.global_access_count++;
pthread_mutex_unlock(&thread_mutex);
}
return NULL;
}
void *context1(void *ptr)
{
unsigned int iter = ITER;
while (iter--) {
wait_event_from_device1();
pthread_mutex_lock(&thread_mutex);
g_status.context_delta--;
g_status.global_access_count++;
pthread_mutex_unlock(&thread_mutex);
}
return NULL;
}
int main(int argc, char **argv)
{
pthread_t tid0, tid1;
int iret;
if ((iret = pthread_create(&tid0, NULL, context0, NULL))) {
fprintf(stderr, "context0 creation error!\n");
return EXIT_FAILURE;
}
if ((iret = pthread_create(&tid1, NULL, context1, NULL))) {
fprintf(stderr, "context1 creation error!\n");
return EXIT_FAILURE;
}
pthread_join(tid0, NULL);
pthread_join(tid1, NULL);
printf("%d, %d\n", g_status.context_delta, g_status.global_access_count);
return 0;
}
我打算将此代码移植到不支持posix的RTOS中,并且我希望自动执行此操作,而无需使用互斥锁或禁用/启用中断。
我该怎么做? 是否可以使用“原子比较和交换功能”(CAS)?
好像在您的示例中,您有两个为不同设备提供服务的线程。 您也许可以使用每个设备的结构来完全锁定。 全局将是所有每个设备统计信息的汇总。 如果确实需要锁,则可以使用CAS,LL / SC或任何受支持的基础原子构造。
我要做的是用我想同时更改的所有字段创建一个联合。 像这样:
union {
struct {
int m_field1;
unsigned short m_field2 : 2,
m_field3 : 1;
BYTE m_field4;
}
unsigned long long m_n64;
TData(const TData& r) { m_n64 = r.m_n64; }
} TData;
您可以像这样在更大的结构中嵌入工会:
struct {
...
volatile TData m_Data;
...
} TBiggerStruct;
然后我做这样的事情:
while (1) {
TData Old = BiggerSharedStruct.m_Data, New = Old;
New.field1++;
New.field4--;
if (CAS(&SharedData.m_n64, Old.m_n64, New.m_n64))
break; // success
}
我想将要同时更改为最小的16位,32位或64位结构的字段打包在一起。 我认为intel上的128位填充不如64位填充快,因此我避免了。 我有一段时间没有进行基准测试了,所以我可能会错了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.