6

这是我的第一个 pthread 程序,我不知道为什么 printf 语句会在子线程中打印两次:

int x = 1;

void *func(void *p)
{
    x = x + 1;
    printf("tid %ld: x is %d\n", pthread_self(), x);
    return NULL;
}

int main(void)
{
    pthread_t tid;
    pthread_create(&tid, NULL, func, NULL);

    printf("main thread: %ld\n", pthread_self());

    func(NULL);
}

在我的平台上观察到的输出(Linux 3.2.0-32-generic #51-Ubuntu SMP x86_64 GNU/Linux):

1.
main thread: 140144423188224
tid 140144423188224: x is 2

2.
main thread: 140144423188224
tid 140144423188224: x is 3

3.
main thread: 139716926285568
tid 139716926285568: x is 2
tid 139716918028032: x is 3
tid 139716918028032: x is 3

4.
main thread: 139923881056000
tid 139923881056000: x is 3
tid 139923872798464tid 139923872798464: x is 2

对于 3,来自子线程的两条输出线

对于 4,与 3 相同,甚至输出也是交错的。

4

3 回答 3

2

线程通常通过时分复用发生。处理器在两个线程之间均匀切换通常效率低下,因为这需要更多的努力和更高的上下文切换。通常你会发现一个线程在切换之前会执行几次(就像示例 3 和 4 的情况一样。子线程在最终终止之前执行了多次(因为主线程退出了)。

例2:不知道为什么x在没有输出的情况下被子线程增加了。

考虑一下。主线程执行。它调用 pthread 并创建一个新线程。新的子线程递增 x。在子线程能够完成 printf 语句之前,主线程开始执行。突然之间,它也增加了 x。然而,主线程也能够运行 printf 语句。突然 x 现在等于 3。主线程现在终止(也导致子 3 退出)。这可能是您的案例 2 中发生的情况。

示例 3 清楚地表明变量 x 已由于低效锁定和堆栈数据损坏而损坏!

有关什么是线程的更多信息。

链接 1 - 关于线程的附加信息

链接 2 - 关于线程的附加信息

您还会发现,因为您使用的是 x 的全局变量,所以对这个变量的访问是在线程之间共享的。这很糟糕.. 非常非常糟糕,因为访问同一变量的线程会创建竞争条件和数据损坏,因为变量 x 的同一寄存器上发生了多次读写。正是出于这个原因,使用互斥锁本质上是在更新变量时创建一个锁,以防止多个线程同时尝试修改同一个变量。互斥锁将确保 x 按顺序更新,而不是像您的情况那样偶尔更新。

有关 Pthreads in General 和 Mutex 锁定示例的更多信息,请参阅此链接。
Pthread 和 Mutex 变量

干杯,
彼得

于 2012-11-25T12:08:04.527 回答
2

唔。您的示例使用来自不同线程的相同“资源”。一种资源是变量 x,另一种是标准输出文件。所以你应该使用如下所示的互斥锁。最后还有一个 pthread_join 等待另一个线程完成它的工作。(通常一个好主意也是检查所有这些 pthread... 调用的返回码)

#include <pthread.h>
#include <stdio.h>
int x = 1;
pthread_mutex_t mutex;

void *func(void *p)
{
    pthread_mutex_lock (&mutex);
    x = x + 1;
    printf("tid %ld: x is %d\n", pthread_self(), x);
    pthread_mutex_unlock (&mutex);
    return NULL;
}

int main(void)
{
    pthread_mutex_init(&mutex, 0);

    pthread_t tid;
    pthread_create(&tid, NULL, func, NULL);

    pthread_mutex_lock (&mutex);
    printf("main thread:  %ld\n", pthread_self());
    pthread_mutex_unlock (&mutex);

    func(NULL);
    pthread_join (tid, 0);
}
于 2012-11-25T12:47:17.400 回答
2

看起来真正的答案是 Michael Burr 的评论,它引用了这个 glibc 错误:https ://sourceware.org/bugzilla/show_bug.cgi?id=14697

总之,glibc 在程序退出期间没有正确处理 stdio 缓冲区。

于 2015-10-16T17:31:36.733 回答