繁体   English   中英

C 中的打印功能互斥锁无法正常工作

[英]C in printing function mutex does not work properly

我正在尝试为线程提供一个 id,然后我想打印我提供的每个线程 id,但是我猜有一种关于互斥锁的情况,我想我正在处理关键部分,但似乎我不能。

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;

struct info{
    int id;
    int flag;
};

void *print_info(void* arg){
    struct info *arg_struct = (struct info*) arg;

    pthread_mutex_lock(&m);

    printf("%d ", arg_struct->id);
    pthread_mutex_unlock(&m);

    pthread_exit(0);

}
int main(int argc, char *argv[])
{
    int number = 10;
    pthread_t tid[number];
    for (int i = 0; i < number; ++i) {
        int info[2];
        info[0] = i;
        info[1] = 0;

        pthread_create(&tid[i], NULL, print_info, &info);
    }
    for (int i = 0; i < number; ++i) {
        pthread_join(tid[i], NULL);
    }

    return 0;
}

这是输出: 1 2 3 4 5 6 7 8 9 9

每次我执行它时都会有所不同,但概念或多或少是相同的,即不打印某些值,而是多次打印一些值。

但预期的输出是这样的:0 1 2 3 4 5 6 7 8 9

[或不按顺序排列的东西,但我猜每个值都会精确打印一次] 谢谢

给每个线程自己的控制数据

正如所写,您的代码不能保证输出数字的顺序——线程执行的顺序取决于 o/s 和硬件。 通过确保每个线程都有自己的struct info可以使用,您可以轻松确保每个 ID 只打印一次。 您现有的代码 (a) 使用结构对数组进行类型化,这是一个坏主意( alk评论),并且 (b) 重用主程序堆栈上的相同空间,以便在线程工作时,主循环改变存储的值是可行的。

这是@ rafix07评论中所说的。 您声称已尝试修复但没有成功。 我必须得出结论,您修改后的代码没有做必要的事情。

您需要使用更像这样的代码(它还会在每次运行结束时打印一个换行符):

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

pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;

struct info
{
    int id;
    int flag;
};

static void *print_info(void *arg)
{
    struct info *arg_struct = (struct info *)arg;

    pthread_mutex_lock(&m);

    printf("%d ", arg_struct->id);
    pthread_mutex_unlock(&m);

    pthread_exit(0);
}

int main(void)
{
    int number = 10;
    pthread_t tid[number];
    struct info info[number];
    for (int i = 0; i < number; ++i)
    {
        info[i].id = i;
        info[i].flag = 0;
        pthread_create(&tid[i], NULL, print_info, &info[i]);
    }

    for (int i = 0; i < number; ++i)
    {
        pthread_join(tid[i], NULL);
    }
    putchar('\n');

    return 0;
}

当我连续运行 10 次时,我得到了输出:

0 7 2 8 3 1 4 9 5 6 
1 8 0 9 2 3 6 5 4 7 
0 4 5 2 3 6 7 1 8 9 
0 1 2 3 4 5 6 7 8 9 
2 7 0 3 5 6 4 8 1 9 
2 0 7 6 3 5 4 8 9 1 
0 9 1 3 5 6 7 2 8 4 
0 7 1 8 4 3 9 2 5 6 
0 7 1 8 3 5 4 2 9 6 
0 3 4 5 6 1 2 8 7 9 

如您所见,每个数字 0..9 在每一行输出中出现一次,但线程执行的顺序并不是确定的。

我不相信互斥体会给你买任何东西。 所有的I / O功能,如printf()必须表现得好像他们使用flockfile()在入境和funlockfile()上的回报。

在运行 macOS Mojave 10.14.6(不要问!)和 GCC 9.2.0 的 MacBook Pro 上测试。

保证顺序

一个简单的修改确保了顺序——主线程在启动线程之前锁定互斥锁,线程在退出之前解锁它。 然而,这意味着没有有意义的并发——你不妨这样写:

for (int i = 0; i < 10; i++)
    printf("%d ", i);
putchar('\n');

这将避免在线程之后启动、运行和清理的所有开销。

修改后的代码只是将一行从print_info()函数移到main()

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

pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;

struct info
{
    int id;
    int flag;
};

static void *print_info(void *arg)
{
    struct info *arg_struct = (struct info *)arg;

    printf("%d ", arg_struct->id);
    pthread_mutex_unlock(&m);

    pthread_exit(0);
}

int main(void)
{
    int number = 10;
    pthread_t tid[number];
    struct info info[number];
    for (int i = 0; i < number; ++i)
    {
        info[i].id = i;
        info[i].flag = 0;
        pthread_mutex_lock(&m);
        pthread_create(&tid[i], NULL, print_info, &info[i]);
    }

    for (int i = 0; i < number; ++i)
    {
        pthread_join(tid[i], NULL);
    }
    putchar('\n');

    return 0;
}

和输出:

0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 

它失败是因为您不断将指向实际上与子线程相同的向量的指针传递给子线程,并在子线程运行时迅速覆盖主线程中的内容。

给定一个加载的系统,您同样可以得到所有 9 的输出。 或者甚至是相反的数字(只是因为我不记得在任何地方都保证线程将按照与创建它们相同的顺序进行调度)。 或者一个非常非常奇怪的数字,因为如果子线程直到主线程开始连接才开始运行,那么“arg”指向的任何内容都将位于 pthread_join 调用堆栈的中间。

所有互斥锁保护您免受同时输出到标准输出的线程的影响。

顺便说一句,将整数数组转换为 2 个整数的结构是未定义的行为,这是完全不同的蠕虫。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM