c - C中的打印函数mutex不能正常工作
问题描述
我试图给线程一个 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
[或者一些不按顺序的东西,但我猜到每个值都会被准确地打印出来]谢谢
解决方案
给每个线程自己的控制数据
如所写,您的代码不能保证输出数字的顺序——线程执行的顺序取决于操作系统和硬件。您可以轻松地确保每个 ID 只打印一次,方法是确保每个线程都有自己的struct info
可使用的线程。您现有的代码 (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
推荐阅读
- python - 根据列过滤熊猫数据框:如果值为该列,则保留所有行
- ns2 - ns2.35 ,从内部调用
- java - 如何识别 JanusGraph 的名称?
- python - python在列中拆分数字
- python - 回调方法未更新 Python 类变量
- jquery - 基于值范围动态更新引导进度条的背景颜色的 jQuery 代码
- javascript - 用于读取 json 输入并映射到 json 输出的 javascript 代码
- css - 多个控件,将 CSS 应用于选定的一个
- git - mvn release:prepare release:perform 从 docker image jenkins git 凭证到 docker image
- python - 在 python 中使用 size 的数组的总大小到底是多少?