2013-09-12 5 views
1

Я хотел бы изменить некоторые элементы структуры атомарно. В моей текущей реализации используются мьютексы для защиты критического кода, и это видно ниже.Как изменить структурные элементы атомарно, не используя блокировки в 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, и я хотел бы сделать эту операцию атомарной без использования семафоров или отключение/включение прерывания.

Как это сделать? Возможно ли это с помощью функции «атомного сравнения и замены» (CAS)?

+0

Требуется ли в вашем коде частые обновления? Как бы вы поместили коэффициент чтения-обновления программы в реальную рабочую нагрузку? – darnir

+0

@ darnir Я не мог задать вам вопрос. Не могли бы вы подробнее рассказать? А также у меня не было возможности измерить реальную рабочую нагрузку, потому что я не мог подключиться к реальному устройству. – albin

+0

Как часто, по вашему мнению, вам потребуется обновить структуру? Вы будете опросить какой-то датчик и постоянно обновлять структуру? Или это очень редко, что вам нужно обновить структуру? – darnir

ответ

0

Похоже, в вашем примере у вас есть обслуживание двух потоков для разных устройств. Возможно, вам удастся полностью блокировать использование структуры каждого устройства. Глобальный будет совокупностью всех статистик каждого устройства. Если вам нужны блокировки, вы можете использовать CAS, LL/SC или любую поддерживаемую базовую атомную конструкцию.

+0

CAS и LL/SC не используют замки – arunmoezhi

0

То, что я делаю, создает объединение со всеми полями, которые я хочу изменить одновременно. как это:

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-битную структуру. Я думаю, что 128 бит на Intel не так быстро, как 64-битные вещи, поэтому я избегаю этого. Я не сравнивал это через некоторое время, поэтому я мог ошибаться.

 Смежные вопросы

  • Нет связанных вопросов^_^