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

时间:2015-08-19 14:06:15

标签: linux multithreading pthreads delay sleep

我无法找到解决问题的正确方法。

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

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

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

1 个答案:

答案 0 :(得分:2)

根据您在评论中的描述,您似乎正在尝试同步2个主题,以便其中一个不会落后于其他主题。

如果是这样的话,你就会以错误的方式解决这个问题。通过休眠进行同步很少是一个好主意,因为调度程序可能会导致不可预测的长延迟,导致其他(慢)线程在运行队列中保持停止状态而不进行调度。即使它在大多数时间都有效,它仍然是一种竞争条件,而且它是一个丑陋的黑客。

鉴于您的使用案例和限制因素,我认为您最好不要使用障碍(请参阅pthread_barrier_init(3))。 Pthread barrier允许您在代码中创建一个集合点,线程可以在其中找到它。

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

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

这是一个模拟快速发送方线程和慢速接收方线程的示例。它们都与屏障同步,以确保发送方在接收方仍在处理其他请求时不做任何工作。线程在其工作单元的末尾同步,但当然,您可以选择每个线程调用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),屏障状态将重置为上次调用{后使用的原始状态{1}},这意味着屏障原子地解锁并重置状态,因此它总是为下一个同步点做好准备,这很棒。

完成障碍后,请勿忘记使用pthread_barrier_init(3)释放相关资源。