【问题标题】:How do I sync my two threads which each use a while loop for a shared resource?如何同步我的两个线程,每个线程都对共享资源使用 while 循环?
【发布时间】:2021-11-26 22:36:01
【问题描述】:

我正在尝试执行此操作,但无法正常工作。 我有一个名为 counter 的全局变量,它从 100 开始,我有两个线程。 如果 counter 为 != 0,则两个线程都在运行 while 循环中递减计数器。 但是,尽管确实将计数器减为 0 的线程将按预期停止运行。但是不递减计数器的线程在它应该停止时继续运行。

我该如何解决这个问题?

下面是我的代码:

int counter = 0;
pthread_mutex_t counter_mutex;

void *Thread1(void *vargs)
{
    while (counter != 0) {
        pthread_mutex_lock(&counter_mutex);
        counter--;
        pthread_mutex_unlock(&counter_mutex);
    }

    sleep(1);
    printf("Completed Thread1\n");
    return NULL;
}

void *Thread2(void *vargs)
{
    while (counter != 0) {
        pthread_mutex_lock(&counter_mutex);
        counter--;
        pthread_mutex_unlock(&counter_mutex);
    }

    sleep(1);
    printf("Completed Thread2\n");
    return NULL;
}

int main(void)
{
    pthread_t tid[2];

    // initialize the mutex
    pthread_mutex_init(&counter_mutex, NULL);

    // create worker threads
    pthread_create(&tid[0], NULL, Thread1, NULL);
    pthread_create(&tid[1], NULL, Thread2, NULL);

    // wait for worker threads to terminate
    pthread_join(tid[0], NULL);
    pthread_join(tid[1], NULL);
    
    // print final counter value
    printf("Counter is %d\n", counter);

    return 0;
}

输出:

Completed Thread1

Thread1 completes but the program runs indefinitely because Thread2 stays in the while loop and doesn't finish.

Or vice versa, where Thread2 completes and then runs indefinitely because Thread1 stays 
in the while loop and doesn't finish.

我真的很困惑如何解决这个问题,因为两个线程应该在 counter == 0 时运行和停止。但是只有计数器递减到 0 的线程会停止,而另一个线程会无限期地运行。

非常感谢任何和所有的帮助!

非常感谢

【问题讨论】:

  • 您有一些未定义的变量(g_Counterg_Mutex)。
  • 也许可以尝试while (counter > 0) 而不是while (counter != 0) - 如果一个线程减少了太多,另一个线程将继续运行。
  • 我修好了。它可能是计数器和互斥锁。我也试过做 counter > 0 。它仍然给出同样的问题。

标签: c multithreading pthreads


【解决方案1】:

在某些时候,当一个线程被阻塞等待锁定互斥体时,另一个线程将减少counter 到零。一旦等待线程获得对锁的访问权,它也会递减,从而产生-1counter 永远不会再接近零,并且会递减,直到通过溢出有符号整数调用 Undefined Behavior

这些都不重要,因为在每个 while 循环谓词中读取 counter 不受互斥锁的保护

while (counter != 0)

这意味着你可以有一个读/写竞争条件。

相反,构建您的锁,使其完全包围所有读取和写入,并调整您的谓词以进行独立检查。

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

int counter = 0;
pthread_mutex_t counter_mutex;

void *runner(void *arg) {
    int *n = arg;
    int done = 0;

    while (!done) {
        pthread_mutex_lock(&counter_mutex);

        if (counter == 0)
            done = 1;
        else
            counter--;

        pthread_mutex_unlock(&counter_mutex);
    }

    printf("Completed Thread %d\n", *n);

    return NULL;
}

int main(void)
{
    pthread_t tid[2];
    int args[2] = { 1, 2 };

    pthread_mutex_init(&counter_mutex, NULL);
    pthread_create(&tid[0], NULL, runner, &args[0]);
    pthread_create(&tid[1], NULL, runner, &args[1]);
    pthread_join(tid[0], NULL);
    pthread_join(tid[1], NULL);

    printf("Counter is %d\n", counter);

    return 0;
}

【讨论】:

  • 我会试试这个。非常感谢详细的回复。
【解决方案2】:

仅供参考:这实际上总是一个坏主意:

while (...trivial condition...) {
    pthread_mutex_lock(&some_mutex);

    ...do some work...

    pthread_mutex_unlock(&some_mutex);
}

它不好的原因是循环试图保持互斥锁几乎 100% 的时间锁定。唯一未锁定互斥锁的时间是循环评估“...琐碎条件...”的短暂时刻

在多个线程中同时执行循环是没有意义的,因为互斥锁会阻止多个线程同时执行“...工作...”。

如果您尝试使用线程进行并行计算,那么这样的方法效果更好:

typedef struct { ... } task_t;

int find_a_task(task_t* task) {
    int result = FALSE;

    pthread_mutex_lock(&some_mutex);
    if (...there's more work to be done...) {
        ...copy from shared data into *task...
        result = TRUE;
    }
    pthread_mutex_unlock(&some_mutex);

    return result;
}

task_t local_task;
while (find_a_task(&local_task)) {

    do_some_heavy_work_on(&local_task);

    pthread_mutex_lock(&some_mutex);
    if (...contents of local_task still are meaningful...) {
        copy from local_task back to shared data structure
    }
    pthread_mutex_unlock(&some_mutex);
}

这个想法是,在不保持任何互斥锁锁定的情况下完成大部分繁重的工作。互斥锁仅在 (a) 进行繁重的工作之前被短暂锁定,将共享数据复制到私有的局部变量中,以及 (b) 在繁重的工作之后,复制结果,如果仍然有效,* 返回到共享数据中。


* 由于某些其他线程更改调用者使用的共享数据项,结果可能仍然无效。这是optimistic locking。这听起来可能效率低下,但在许多程序中,在执行繁重的工作时不保持互斥锁锁定所获得的效率远远高于由于线程偶尔重复或使彼此的工作无效而损失的效率。 p>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-01
    相关资源
    最近更新 更多