Linux 多线程,暂停一个线程,同时继续 运行 同一进程中的其他线程

Linux multi-thread, pausing one thread while continue running the other threads within the same process

我找不到合适的方法解决我的问题。

如果我在一个进程中有多个线程。我只想让一个线程休眠,而 运行 同一进程中的其他线程,是否有任何预定义的语法,或者我是否必须自己实现(睡眠)?

理想情况下,我想在睡眠时间从一个线程向另一个线程发送一个指示。

已编辑 (2015-08-24) 我有两个主线程,一个用于通过网络发送数据,另一个从网络接收数据。除了抖动之外,接收线程还进行验证和验证以及一些文件管理,这可能会及时导致它拖延。我喜欢做的是向发送者添加微睡眠之类的东西,以便接收者能够赶上。 sched_yield() 在这种情况下无济于事,因为硬件有一个多核 CPU 超过 40 个内核。

根据您在评论中的描述,您似乎正在尝试同步 2 个线程,以便其中一个线程不会落后于另一个线程太远。

如果是这样,那你就走错了路。通过睡眠进行同步很少是一个好主意,因为调度程序可能会导致不可预测的长时间延迟,导致另一个(慢速)线程在 运行 队列中保持停止状态而没有被调度。即使它在大部分时间都有效,它仍然是一个竞争条件,而且是一个丑陋的 hack。

鉴于您的用例和限制,我认为您最好使用障碍(请参阅 pthread_barrier_init(3))。 Pthread 屏障允许您在代码中创建一个线程可以赶上的集合点。

您调用 pthread_barrier_init(3) 作为初始化代码的一部分,指定将使用该屏障同步的线程数。在这种情况下,它是 2.

然后,线程通过调用 pthread_barrier_wait(3) 与其他线程同步。调用阻塞,直到 pthread_barrier_init(3) 调用 pthread_barrier_wait(3) 中指定的线程数,此时在 pthread_barrier_wait(3) 中阻塞的每个线程都变为 运行nable 并且循环再次开始。从本质上讲,障碍创造了一个同步点,在每个人都到达之前没有人可以前进。我想这正是您要找的。

下面是一个模拟快速发送线程和慢速接收线程的示例。它们都与屏障同步,以确保发送方在接收方仍在处理其他请求时不做任何工作。线程在其工作单元结束时同步,但当然,您可以选择每个线程调用的位置 pthread_barrier_wait(3),从而准确控制线程同步的时间(和位置)。

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

pthread_barrier_t barrier;

void *sender_thr(void *arg) {
    printf("Entered sender thread\n");

    int i;
    for (i = 0; i < 10; i++) {
        /* Simulate some work (500 ms) */
        if (usleep(500000) < 0) {
            perror("usleep(3) error");
        }

        printf("Sender thread synchronizing.\n");
        /* Wait for receiver to catch up */
        int barrier_res = pthread_barrier_wait(&barrier);
        if (barrier_res == PTHREAD_BARRIER_SERIAL_THREAD)
            printf("Sender thread was last.\n");
        else if (barrier_res == 0)
            printf("Sender thread was first.\n");
        else
            fprintf(stderr, "pthread_barrier_wait(3) error on sender: %s\n", strerror(barrier_res));
    }

    return NULL;
}

void *receiver_thr(void *arg) {
    printf("Entered receiver thread\n");

    int i;
    for (i = 0; i < 10; i++) {
        /* Simulate a lot of work */
        if (usleep(2000000) < 0) {
            perror("usleep(3) error");
        }

        printf("Receiver thread synchronizing.\n");
        /* Catch up with sender */
        int barrier_res = pthread_barrier_wait(&barrier);
        if (barrier_res == PTHREAD_BARRIER_SERIAL_THREAD)
            printf("Receiver thread was last.\n");
        else if (barrier_res == 0)
            printf("Receiver thread was first.\n");
        else
            fprintf(stderr, "pthread_barrier_wait(3) error on receiver: %s\n", strerror(barrier_res));
    }

    return NULL;
}

int main(void) {
    int barrier_res;
    if ((barrier_res = pthread_barrier_init(&barrier, NULL, 2)) != 0) {
        fprintf(stderr, "pthread_barrier_init(3) error: %s\n", strerror(barrier_res));
        exit(EXIT_FAILURE);
    }

    pthread_t threads[2];

    int thread_res;
    if ((thread_res = pthread_create(&threads[0], NULL, sender_thr, NULL)) != 0) {
        fprintf(stderr, "pthread_create(3) error on sender thread: %s\n", strerror(thread_res));
        exit(EXIT_FAILURE);
    }
    if ((thread_res = pthread_create(&threads[1], NULL, receiver_thr, NULL)) != 0) {
        fprintf(stderr, "pthread_create(3) error on receiver thread: %s\n", strerror(thread_res));
        exit(EXIT_FAILURE);
    }

    /* Do some work... */

    if ((thread_res = pthread_join(threads[0], NULL)) != 0) {
        fprintf(stderr, "pthread_join(3) error on sender thread: %s\n", strerror(thread_res));
        exit(EXIT_FAILURE);
    }
    if ((thread_res = pthread_join(threads[1], NULL)) != 0) {
        fprintf(stderr, "pthread_join(3) error on receiver thread: %s\n", strerror(thread_res));
        exit(EXIT_FAILURE);
    }

    if ((barrier_res = pthread_barrier_destroy(&barrier)) != 0) {
        fprintf(stderr, "pthread_barrier_destroy(3) error: %s\n", strerror(barrier_res));
        exit(EXIT_FAILURE);
    }

    return 0;
}

请注意,如 pthread_barrier_wait(3) 的联机帮助页中所述,一旦所需数量的线程调用 pthread_barrier_wait(3),屏障状态将重置为上次调用后使用的原始状态到pthread_barrier_init(3),这意味着屏障以原子方式解锁并重置状态,因此它始终为下一个同步点做好准备,这太棒了。

完成屏障后,不要忘记使用 pthread_barrier_destroy(3) 释放相关资源。