【问题标题】:Functionality of pthread_join() in Ubuntu CUbuntu C 中 pthread_join() 的功能
【发布时间】:2021-07-18 17:59:06
【问题描述】:

使用 pthread 库编写一个小的 C 代码。我对这个代码的要求是先存钱再提钱。

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

int counter = 0;
void *increase();
void *decrease();

int balance = 500;

void *deposit(void*);
void *withdraw(void*);


int main() {

    pthread_t t_inc, t_dec;
    int dep_money = 300;
    int wd_money = 100;

    pthread_create(&t_inc, NULL, deposit, &dep_money);
    pthread_create(&t_dec, NULL, withdraw, &wd_money);

    // Wait until the thread is finished
    pthread_join(t_inc, NULL);
    pthread_join(t_dec, NULL);
    }
    return 0;
}

// Functions for thread
void *deposit(void *args) {
    int *money = (int *)args;
    balance += *money;
    printf("Deposit: New balance: %d\n", balance);
    return NULL;
}

void *withdraw(void *args) {
    int *money = (int *)args;

    if (balance < *money) {
        printf("Not enough balance\n");
    } else {
        balance -= *money;
        printf("Withdraw: New balance: %d\n", balance);
    }
    return NULL;
}

我在 2 个不同的操作系统上使用了这个代码,Ubuntu 和 macOS。由于某种原因,我得到了 2 个不同的结果。

对于 macOS:

存款:新余额:800

提现:新余额:700

对于 Ubuntu:

提现:新余额:400

存款:新余额:700

但是当我在 Ubuntu 中更改 pthread_join() 的顺序时,它按照我想要的顺序运行。

pthread_create(&t_inc, NULL, deposit, &dep_money);
pthread_join(t_inc, NULL);

pthread_create(&t_dec, NULL, withdraw, &w_money);
pthread_join(t_dec, NULL);

总之,我的问题是为什么在 Ubuntu 中运行的第一个代码中它没有作为 pthread_join(t_inc, NULL); 的第一顺序运行。然后是第二个 pthread_join(t_dec, NULL);相反,它运行相反?而且我必须在 pthread_create() 之后立即调用 pthread_join() 才能让它按顺序工作,因为我还没有创建第二个线程,所以我认为它效率不高。

【问题讨论】:

  • 在我看来这只是一个竞争条件,与您使用的操作系统无关。
  • 创建两个线程只是为了完成两个不能重叠的工作,这怎么能有效率呢?使用一个线程而不是三个线程不是更有效吗?

标签: c ubuntu pthreads pthread-join


【解决方案1】:

这只是一个竞争条件。调用一个线程的pthread_createbefore 另一个并不能保证第二个线程应该由操作系统在第一个线程之后调度。所以调用

pthread_create(&t_inc, NULL, deposit, &dep_money);
pthread_create(&t_dec, NULL, withdraw, &wd_money);

并不意味着您将在运行withdraw() 的线程之前调用运行deposit() 的线程。这完全取决于操作系统何时实际安排它们,作为程序员,不应对此做出任何假设。因此,结果中的差异是因为任何一个线程都可能在之前运行过。

所以,回答你的问题

我的问题是为什么在 Ubuntu 中运行的第一个代码中它没有运行为 pthread_join(t_inc, NULL) 的第一阶;然后是第二个 pthread_join(t_dec, NULL);而是相反?

不要对线程实际运行的顺序有任何期望。

打电话

pthread_create(&t_inc, NULL, deposit, &dep_money);
pthread_join(t_inc, NULL);

pthread_create(&t_dec, NULL, withdraw, &w_money);
pthread_join(t_dec, NULL);

将始终有效,因为您基本上已序列化线程创建,并且调用 deposit() 的线程应始终在运行 withdraw() 的线程生成之前完成,因此它适用于所有操作系统。

编辑:

为了完整起见,正如您所提到的,创建线程并立即调用 join() 并没有多大用处,因为它与按顺序调用函数 deposit()withdraw() 一样好,因为这里是 @987654333 @ 和 withdraw() 并没有真正做很多重要的工作,这些工作可能会使主线程停止,阻止它继续执行其他任务。此外,您通常需要处理共享变量。例如如果您只有一个变量amount,然后每个线程更新相同的值,一个添加余额,另一个减去它,那么您可能需要像 mutex/condition_variable 这样的构造来实现您想要的结果,而无需竞争条件。

【讨论】:

  • @JohnBollinger 当然。在这种情况下,直接调用函数可能就足够了。为了完整起见,让我也更新一下答案。
猜你喜欢
  • 2019-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-23
  • 2017-04-18
  • 2012-10-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多