首页 > 解决方案 > Linux C,如何安排 10 个等待线程在 FIFO 中执行?

问题描述

我正在使用以下条件线程使用 FIFO 调度锁定 10 个线程,我需要按照线程到达 pthread_cond_wait(&cvv, &lock); 的顺序解锁线程 我需要知道这是否可能,或者不能保证会出现这种情况。

struct sched_param param = {.sched_priority = 10};
pthread_cond_t cvv = (pthread_cond_t) PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;

void *thread(void *v) {
    pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);
    int index = *((int *)v);
    printf("Locking [%d] and waiting\n", index);
    pthread_mutex_lock(&lock);
    pthread_cond_wait(&cvv, &lock);
    printf("Unlockd [%d] => %d\n", index, clock());
    pthread_mutex_unlock(&lock);
    return NULL;
}

int main(int argc, char** argv) {
    for (int i = 0; i < 10; i++) {
        t = (pthread_t *) malloc(sizeof (pthread_t));
        int *x = malloc(sizeof (int));
        *x = i;
        pthread_create(t, NULL, thread, x);
    }
    for (int i = 0; i < 10; i++) {
        pthread_cond_signal(&cvv);
    }
}

输出未按升序排列

Locking [0] and waiting
Locking [1] and waiting
Locking [2] and waiting
Locking [3] and waiting
Locking [4] and waiting
Locking [5] and waiting
Locking [6] and waiting
Locking [7] and waiting
Locking [8] and waiting
Locking [9] and waiting

Unlocked [0] => 7043
Unlocked [8] => 7084
Unlocked [6] => 7100
Unlocked [2] => 7130
Unlocked [5] => 7294
Unlocked [7] => 7362
Unlocked [3] => 7407
Unlocked [1] => 7463
Unlocked [9] => 7482
Unlocked [4] => 7559

标签: clinuxmultithreadingposixthreadpool

解决方案


pthread_setschedparam您可能无法使用,因为它需要特权。您不检查这些调用的返回值,但您可能会发现它们以EPERM. 他们为我这样做。

我需要按照线程到达 pthread_cond_wait(&cvv, &lock); 的顺序解锁线程 我需要知道这是否可能,或者不能保证会出现这种情况。

是的,你可以这样做,但你需要自己动手。这是一个可以实现它的方案:

  • 建立三个全局计数器,例如inoutnext,对它们的访问受互斥锁保护。将它们全部初始化为 0。

  • 每个线程都像这样通过锁:

    • 在等待 CV 之前,它会递增in并记录新值。这是它的“票”。
    • 它测试其票证是否等于nextnext小于或等于out,并且仅当不满足其中一个或两个条件时才等待 CV。
    • 如果它确实等待,那么当它返回时,它会循环返回以针对next.
    • 在它通过锁之前,它会递增next.
    • 最后,它向 CV 广播(这可能是在解锁互斥锁之前或之后)
  • 解锁下一个线程,

    • 增量out
    • 如果next仍为 0,则也将其递增
    • 打电话pthread_cond_broadcast pthread_cond_signal

当然,所有对inout和的访问都next必须在互斥锁的保护下执行,该互斥锁应该与 CV 使用的相同。

请注意,当当前没有线程被锁定时,该方案允许线程前瞻性地授予解锁。这实际上将解决您当前实现的一个问题,但如果您愿意,您可以仅使用inand对其进行重新设计next,使执行解锁的线程等待in超过next。这可以通过使用相同的 CV 来实现。细节留作练习。


推荐阅读