1

構造のいくつかの要素をアトミックに変更したいと思います。私の現在の実装ではミューテックスを使用して重要なコードを保護しています。これを以下に示します。

#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)を使えば可能でしょうか?

4

2 に答える 2

0

あなたの例では、異なるデバイスにサービスを提供する2つのスレッドがあるようです。デバイスごとの構造を使用して、ロックを完全になくすことができるかもしれません。グローバルは、すべてのデバイスごとの統計の集計になります。ロックが必要な場合は、CAS、LL/SC、またはサポートされている基本的なアトミック コンストラクトを使用できます。

于 2013-09-12T20:46:56.353 に答える
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 ビットのものは 64 ビットのものほど速くないと思うので、私はそれを避けています。しばらくベンチマークしていないので、間違っている可能性があります。

于 2014-05-15T05:45:35.487 に答える