【问题标题】:C++ Using semaphores instead of busy waitingC++ 使用信号量而不是忙于等待
【发布时间】:2012-11-26 04:03:26
【问题描述】:

我正在尝试学习信号量和多线程。我正在使用的示例创建 1 到 t 个线程,每个线程指向下一个线程,最后一个线程指向第一个线程。该程序允许每个线程依次轮流,直到所有线程都轮流 n 轮。那是程序结束的时候。唯一的问题是在 tFunc 函数中,我正忙着等到轮到特定线程。我想知道如何使用信号量来让所有线程进入睡眠状态,并且只有在轮到它执行时才唤醒一个线程以提高效率。

int turn = 1;
int counter = 0;
int t, n;

struct tData {
        int me;
        int next;
};

void *tFunc(void *arg) {
        struct tData *data;
        data = (struct tData *) arg;
        for (int i = 0; i < n; i++) {
            while (turn != data->me) {
        }
        counter++;
        turn = data->next;
    }
}

int main (int argc, char *argv[]) {
    t = atoi(argv[1]);
    n = atoi(argv[2]);
    struct tData td[t];
    pthread_t threads[t];
    int rc;

    for (int i = 1; i <= t; i++) {
        if (i == t) {
            td[i].me = i;
            td[i].next = 1;
        }
        else {
            td[i].me = i;
            td[i].next = i + 1;
        }
        rc = pthread_create(&threads[i], NULL, tFunc, (void *)&td[i]);
        if (rc) {
            cout << "Error: Unable to create thread, " << rc << endl;
            exit(-1);
        }
    }
    for (int i = 1; i <= t; i++) {
        pthread_join(threads[i], NULL);
    }
    pthread_exit(NULL);
}

【问题讨论】:

  • while (turn != data-&gt;me) {} ??
  • C++ 数组从零开始 - for (int i = 1; i &lt;= t; i++) 将超出数组边界。
  • 它只是循环直到轮到它。我只在网上找到了简单的信号量示例并尝试实现它......但我认为我需要多个信号量,现在我迷失了如何实现它。
  • 嗯...我刚刚意识到它确实超出了界限,但由于某种原因它仍然可以编译并运行良好...

标签: c++ multithreading pthreads posix semaphore


【解决方案1】:

使用互斥锁和条件变量。这是一个工作示例:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

int turn = 1;
int counter = 0;
int t, n;

struct tData {
        int me;
        int next;
};

pthread_mutex_t mutex;
pthread_cond_t cond;

void *tFunc(void *arg)
{
    struct tData *data;
    data = (struct tData *) arg;
    pthread_mutex_lock(&mutex);
    for (int i = 0; i < n; i++)
    {
        while (turn != data->me)
            pthread_cond_wait(&cond, &mutex);
        counter++;
        turn = data->next;
        printf("%d goes (turn %d of %d), %d next\n", data->me, i+1, n, turn);
        pthread_cond_broadcast(&cond);
    }
    pthread_mutex_unlock(&mutex);
}

int main (int argc, char *argv[]) {
    t = atoi(argv[1]);
    n = atoi(argv[2]);
    struct tData td[t + 1];
    pthread_t threads[t + 1];
    int rc;

    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond, NULL);

    for (int i = 1; i <= t; i++)
    {
        td[i].me = i;
        if (i == t)
            td[i].next = 1;
        else
            td[i].next = i + 1;

        rc = pthread_create(&threads[i], NULL, tFunc, (void *)&td[i]);
        if (rc)
        {
            printf("Error: Unable to create thread: %d\n", rc);
            exit(-1);
        }
    }
    void *ret;
    for (int i = 1; i <= t; i++)
        pthread_join(threads[i], &ret);
}

【讨论】:

    【解决方案2】:

    使用N+1 信号量。启动时,线程i 等待信号量i。醒来时“轮到and signals semaphorei + 1`。

    主线程产生N,线程,信号量0并等待信号量N

    伪代码:

    sem s[N+1];
    
    thread_proc (i):
      repeat N:
          wait (s [i])
          do_work ()
          signal (s [i+1])
    
    main():
      for i in 0 .. N:
        spawn (thread_proc, i)
    
      repeat N:    
          signal (s [0]);
          wait (s [N]);
    

    【讨论】:

      【解决方案3】:

      每个线程有一个信号量。在其信号量上设置每个线程 wait,如果 sem_wait 返回 EINTR,则重试。一旦它完成了它的工作,让它post 到下一个线程的信号量。这通过一次只唤醒一个线程来避免 David 的解决方案的“雷鸣般的羊群”行为。

      还要注意,由于您的信号量永远不会有大于 1 的值,因此您可以为此使用 pthread_mutex_t

      【讨论】:

        猜你喜欢
        • 2011-12-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-30
        • 1970-01-01
        • 1970-01-01
        • 2013-03-05
        相关资源
        最近更新 更多