pthread_cond_wait потерял сигнал от pthread_cond_signal

0

Я создал несколько потоков и хочу запускать их с помощью циклического режима, используя переменную условия и сигнал (pthread_cond_wait & pthread_cond_signal).

Я использовал два подхода, один подход работает, но тратит процессор, тогда как другой подход не работает, не теряя процессор.

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

Первый подход:

Темы создаются и ждут переменной условия и непрерывно проверяют переменную, называемую state (внутри цикла while).

когда state == my_id поток с my_id активирован, и затем он сигнализирует о следующем потоке my_id + 1 и так далее.

DRAWBACK: Очистка процессора

Второй подход:

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

Есть ли что-то вроде "Self Signaling" или другим способом отправки сигнала, когда сигнал потерян?

Я использую g++ под linux. Любая подсказка будет высоко оценена. Заранее спасибо.

Программа с первым подходом здесь круглая.

Вот моя программа со вторым подходом:

#include <pthread.h>
#include <stdio.h>
#include <iostream>
#include <mutex>          // std::mutex


#define MULTIPLE_THREADS 2
#define NTHREADS MULTIPLE_THREADS*64
#define NO_OF_LOOP 1


pthread_cond_t      cond[NTHREADS];
pthread_mutex_t     mutex1 = PTHREAD_MUTEX_INITIALIZER;


using namespace std;



/* This is our thread function.  It is like main(), but for a thread*/
void *threadA(void *arg)
{ 
    long my_id = (long)arg;
    int i = 0;

    while(i < NO_OF_LOOP)
    {


        // Awaken or unblocked by thread (i-1) 
        pthread_mutex_lock(&mutex1);
        pthread_cond_wait(&cond[my_id], &mutex1);
        pthread_mutex_unlock(&mutex1);

        printf("I am thread - %ld",my_id);
        ++i;


         /* wake up thread i+1 */
        pthread_mutex_lock(&mutex1);
        pthread_cond_signal(&cond[(my_id + 1) % NTHREADS]);
        pthread_mutex_unlock(&mutex1);      
    }

    return NULL;
}

int main(void)
{

    pthread_t             threadid[NTHREADS];


    // Initialization   
    for(int i=0;i<NTHREADS;i++)
    cond[i]= PTHREAD_COND_INITIALIZER;

    //printf("Create %d threads\n", NTHREADS);
    for(long i=0; i<NTHREADS; ++i) {
    pthread_create(&threadid[i], NULL, threadA, (void *)i);
    //printf("Thread created=%d\n", i);
    }

    //  printf("Wait for threads and cleanup\n");
    for (long i=0; i<NTHREADS; ++i) {
    pthread_join(threadid[i], NULL);
    }

    return 0;
}
  • 0
    изменить его! просто не сигнализируй, прежде чем ждать.
  • 0
    @Dabo Как я могу отправить сигнал позже? Должен ли я использовать сон в основном потоке?
Показать ещё 1 комментарий
Теги:
multithreading
linux-kernel

1 ответ

2

Таким образом вы не можете использовать переменную условия. Вам всегда нужен предикат. То есть вам нужна переменная, которую вы можете проверить, произошло ли событие.

Простое выключение слепых pthread_cond_wait и pthread_cond_signal заставит вас потерять события. Там могут быть побочные пробуждения, и если поток, который вы сигнализируете, не заблокирован в pthread_cond_wait(), он пропустит событие (pthread_cond_signal() не стоит в очереди).

Вам понадобится нечто подобное (не проверено):

pthread_cond_t      cond[NTHREADS];
int                 wakeup[NTHREADS];
pthread_mutex_t     mutex1 = PTHREAD_MUTEX_INITIALIZER;


using namespace std;



/* This is our thread function.  It is like main(), but for a thread*/
void *threadA(void *arg)
{ 
    long my_id = (long)arg;
    int i = 0;

    while(i < NO_OF_LOOP)
    {


        // Awaken or unblocked by thread (i-1) 
        pthread_mutex_lock(&mutex1);
        while (!wakeup[my_id]) {
            pthread_cond_wait(&cond[my_id], &mutex1);
        }
        wakeup[my_id] = 0;
        pthread_mutex_unlock(&mutex1);

        printf("I am thread - %ld",my_id);
        ++i;

        pthread_mutex_lock(&mutex1);
        //tell thread i to wake up
        wakeup[(my_id + 1) % NTHREADS] = 1; 
        pthread_cond_signal(&cond[(my_id + 1) % NTHREADS]);
        pthread_mutex_unlock(&mutex1);      
    }

    return NULL;
}
int main(void)
{

    pthread_t             threadid[NTHREADS];
    wakeup[0] = 1; //let thread 0 start.

РЕДАКТИРОВАТЬ. Еще одна ошибка с #define NTHREADS MULTIPLE_THREADS*64 тоже. Выражение (my_id + 1) % NTHREADS не будет правильно оценено, макрос должен быть

 #define NTHREADS (MULTIPLE_THREADS*64)

Поскольку stdout обычно буферизируется по строке, добавьте новую строку в ваш printf, чтобы вы могли сразу увидеть вывод.

 printf("I am thread - %ld\n",my_id);
  • 0
    спасибо за объяснение необходимости предиката для условной переменной, которую я использовал в первом подходе, и вы также предлагаете подобное. У меня есть одно сомнение или вопрос: не думаете ли вы, что при проверке предиката происходит много потерь процессора? Кстати, хотя кажется, что логика верна (я использовал ту же логику, за исключением того, что я использовал только одну переменную состояния), но ваш код не работает.
  • 0
    @bholanath Процессор не теряется, pthread_cond_wait () блокирует поток. Я не знаю, как вы можете сделать это, имея только одну переменную состояния (и я не уверен, что вы подразумеваете под этим, похоже, у вас есть только 1 переменная вместо массива, как массив wakeup - это будет не работа). Обратите внимание, что wakeup[0] = 1; в main () довольно важно.
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню