c - 如何使用 C 线程从头到尾读取文件?
问题描述
我需要用 2 个线程读取文件,其中一个将从头到中读取文件,另一个将从头到中读取文件。我的文件中有 10 个浮点数。前 5 个浮点数将由一个线程求和,最后 5 个浮点数将由另一个线程求和。func1 没问题,但我无法处理 func2 部分。
float sum=0,sum1=0,sum2=0,flo;
int i=0;
FILE *fp;
void *func1(void *param) {
for(i=1;i<=5;i++) {
fscanf(fp,"%f",&flo);
sum1=flo+sum1;
}
pthread_exit(0);
}
int main() {
pthread_t tid;
pthread_attr_t attr;
pthread_attr_init(&attr);
fp = fopen("input.txt","r");
pthread_create(&tid, &attr, func1,fp);
pthread_create(&tid, &attr, func2,fp);
pthread_join(tid, NULL);
}
解决方案
到目前为止,最简单的技术是使用单个线程进行读取。但是,鉴于这是使用 POSIX 线程的练习,那么:
- 您应该始终检查来自
fscanf()
线程或无线程的返回值。 - 即使在非线程程序中,您也应该避免使用全局变量。
- 使用线程和
i
,sum1
并且flo
所有这些都是全局的,您正在为可怕的竞争条件做好准备。您应该有互斥锁以防止对这些变量的并发访问。或者,更好的是,将它们全部设为线程函数的本地。 - 您还需要使函数返回适当的值。
- 您应该使用传递给线程函数的参数。
- 您应该将线程 ID 值保存在单独的变量中,这样您就可以等待两个线程完成;您的代码只等待一个线程完成(第二个)。
- 您应该打印结果。
- 您不必担心文件流上的同步 — POSIX 无论如何都要求这样做(请参阅
flockfile()
及其近亲都记录在同一页面上)。 - 您应该同时提供
func1()
并func2()
创建一个 MCVE ( Minimal, Complete, Verifiable Example。我假设两个线程都可以使用相同的函数,这在上下文中不是一个冒险的假设。
把这些放在一起会导致:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
struct tcb
{
FILE *fp;
double sum;
int thread_num;
};
static void *func1(void *param)
{
struct tcb *tcb = param;
double sum1 = 0.0, flo;
for (int i = 1; i <= 5; i++)
{
if (fscanf(tcb->fp, "%lf", &flo) != 1)
{
fprintf(stderr, "Thread %d failed to read value %d\n", tcb->thread_num, i);
pthread_exit(0);
}
sum1 += flo;
}
tcb->sum = sum1;
pthread_exit(0);
}
int main(void)
{
FILE *fp;
pthread_t tid1;
pthread_t tid2;
struct tcb tcb[2];
pthread_attr_t attr;
pthread_attr_init(&attr);
const char *filename = "input.txt";
if ((fp = fopen(filename, "r")) == NULL)
{
fprintf(stderr, "Failed to open file %s for reading\n", filename);
exit(1);
}
tcb[0].fp = fp;
tcb[0].thread_num = 0;
tcb[0].sum = 0.0;
tcb[1].fp = fp;
tcb[1].thread_num = 1;
tcb[1].sum = 0.0;
pthread_create(&tid1, &attr, func1, &tcb[0]);
pthread_create(&tid2, &attr, func1, &tcb[1]);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
printf("Total from thread 0 = %f\n", tcb[0].sum);
printf("Total from thread 1 = %f\n", tcb[1].sum);
printf("Grand total = %f\n", tcb[0].sum + tcb[1].sum);
return 0;
}
还有其他方法可以处理线程函数的输入和输出,但是创建一个简单的结构似乎非常简单和合适。
给定数据文件 ( input.txt
):
23.192048
4.128715
3.465737
74.307105
4.329846
6.098813
9.497566
6.988740
11.530497
53.262049
9.469198
41.305744
一次运行的输出是:
Total from thread 0 = 87.377665
Total from thread 1 = 109.423451
Grand total = 196.801116
其他运行给出了不同的值(另一运行反转了两个结果)。这两个总和对应于数据文件的第 6-10 行和第 1-5 行(有 12 行)。这表明一个线程设法获得调度并读取其数据配额,然后让另一个线程读取下一个数据配额。添加更多线程(使用循环和线程 ID 值数组)和更多数据可能会显示 I/O 操作的不同交错顺序。
推荐阅读
- html - 2x 和最小宽度的图像 srcset 组合?
- linux - Unix / Linux 命令将 30 分钟添加到数字字符串
- r - 如何在闪亮的 rhandsontable 中启用手动行移动?
- azure - 获取应用程序网关子网中可用 IP 的列表。希望动态成为静态
- cpu - (批处理)多核系统的“wmic cpu”问题
- javascript - Dart:从 Firebase 快照中解码 Json
- jakarta-ee - ConstraintValidator 两次调用 isValid() 方法
- javascript - 如何禁用按钮上的第三方事件处理程序?
- c - c语言中的逻辑门模拟
- html - 如何超链接到我页面的某个部分?