Переменные условия pthread против событий win32 (linux против windows-ce) - PullRequest
6 голосов
/ 16 января 2012

Я делаю оценку производительности между Windows CE и Linux на плате arm imx27. Код уже был написан для CE и измеряет время, необходимое для выполнения различных вызовов ядра, таких как использование примитивов ОС, таких как мьютекс и семафоры, открытие и закрытие файлов и работа в сети.

Во время переноса этого приложения в Linux (pthreads) я наткнулся на проблему, которую не могу объяснить. Почти все тесты показали увеличение производительности от 5 до 10 раз, но не моя версия win32 events (SetEvent и WaitForSingleObject), на самом деле CE " выиграл "этот тест.

Для эмуляции поведения я использовал переменные условия pthreads (я знаю, что моя реализация не полностью эмулирует версию CE, но этого достаточно для оценки) .

Тестовый код использует два потока, которые "пинг-понг" друг с другом, используя события.


Код Windows:

Резьба 1: (нить, которую я измеряю)

HANDLE hEvt1, hEvt2;
hEvt1 = CreateEvent(NULL, FALSE, FALSE, TEXT("MyLocEvt1"));
hEvt2 = CreateEvent(NULL, FALSE, FALSE, TEXT("MyLocEvt2"));

ResetEvent(hEvt1);
ResetEvent(hEvt2);

for (i = 0; i < 10000; i++)
{
    SetEvent (hEvt1);
    WaitForSingleObject(hEvt2, INFINITE);
}        

Тема 2: (просто "отвечает")

while (1)
{
    WaitForSingleObject(hEvt1, INFINITE);
    SetEvent(hEvt2);
}

Код Linux:

Резьба 1: (нить, которую я измеряю)

struct event_flag *event1, *event2;
event1 = eventflag_create();
event2 = eventflag_create();

for (i = 0; i < 10000; i++)
{
    eventflag_set(event1);
    eventflag_wait(event2);
}

Тема 2: (просто "отвечает")

while (1)
{
    eventflag_wait(event1);
    eventflag_set(event2);
}

Моя реализация eventflag_*:

struct event_flag* eventflag_create()
{
    struct event_flag* ev;
    ev = (struct event_flag*) malloc(sizeof(struct event_flag));

    pthread_mutex_init(&ev->mutex, NULL);
    pthread_cond_init(&ev->condition, NULL);
    ev->flag = 0;

    return ev;
}

void eventflag_wait(struct event_flag* ev)
{
    pthread_mutex_lock(&ev->mutex);

    while (!ev->flag)
        pthread_cond_wait(&ev->condition, &ev->mutex);

    ev->flag = 0;

    pthread_mutex_unlock(&ev->mutex);
}

void eventflag_set(struct event_flag* ev)
{
    pthread_mutex_lock(&ev->mutex);

    ev->flag = 1;
    pthread_cond_signal(&ev->condition);

    pthread_mutex_unlock(&ev->mutex);
}

И struct:

struct event_flag
{
    pthread_mutex_t mutex;
    pthread_cond_t  condition;
    unsigned int    flag;
};

Вопросы:

  • Почему я не вижу здесь повышения производительности?
  • Что можно сделать для повышения производительности (например, существуют ли более быстрые способы реализации поведения CE)?
  • Я не привык к кодированию pthreads, есть ли ошибки в моей реализации, которые могут привести к снижению производительности?
  • Есть ли для этого альтернативные библиотеки?

Ответы [ 2 ]

3 голосов
/ 17 января 2012

Обратите внимание, что вам не нужно удерживать мьютекс при вызове pthread_cond_signal(), поэтому вы можете повысить производительность реализации переменной условия "событие", освободив мьютекс перед сигналом условия:

void eventflag_set(struct event_flag* ev)
{
    pthread_mutex_lock(&ev->mutex);

    ev->flag = 1;

    pthread_mutex_unlock(&ev->mutex);

    pthread_cond_signal(&ev->condition);
}

Это может помешать немедленной блокировке пробужденного потока на мьютексе.

0 голосов
/ 13 марта 2013

Этот тип реализации работает, только если вы можете позволить себе пропустить событие.Я только что проверил это и столкнулся со многими тупиками.Основная причина этого заключается в том, что условные переменные пробуждают только поток, который уже ожидает.Переданные ранее сигналы теряются.

Нет счетчика, связанного с условием, которое позволяет ожидающему потоку просто продолжать работу, если условие уже было сигнализировано.События Windows поддерживают этот тип использования.

Я не могу придумать лучшего решения, чем взять семафор (версия POSIX очень проста в использовании), который инициализируется нулем, используя sem_post() для set() иsem_wait() для wait().Вы наверняка можете придумать, как увеличить количество семафоров до 1, используя sem_getvalue()

Тем не менее я понятия не имею, являются ли семафоры POSIX просто аккуратным интерфейсом для семафоров Linux или какова производительностьштрафы.

...