【问题标题】:Using pthread to have one thread do all disk writing that other threads send it?使用 pthread 让一个线程完成其他线程发送的所有磁盘写入?
【发布时间】:2020-04-26 10:33:32
【问题描述】:

我现在正在尝试创建一个程序,其中多个线程正在查询需要处理然后写入磁盘的数据。目前我正在使用 pragma 和 pragma critical 以确保按预期写入数据。

这是相当昂贵的,因为线程必须相互等待。我读到应该可以让一个线程为您处理所有对磁盘的写入,而其他线程可以专注于获取传入的数据并对其进行解析。我该怎么做呢?

该程序是一个基于 XDP 的数据包解析器,它仅存储有关每个数据包的特定信息。代码基于这里的项目代码:https://github.com/xdp-project/xdp-tutorial/blob/master/tracing04-xdp-tcpdump/xdp_sample_pkts_user.c


    static int print_bpf_output(void *data, int size)
    {
        struct {
            __u16 cookie;
            __u16 pkt_len;
            __u8  pkt_data[SAMPLE_SIZE];
        } __packed *e = data;
        struct pcap_pkthdr h = {
            .caplen = SAMPLE_SIZE,
            .len    = e->pkt_len,
        };
        struct timespec ts;
        int i, err;

        if (e->cookie != 0xdead) {
            printf("BUG cookie %x sized %d\n",
                   e->cookie, size);
            return LIBBPF_PERF_EVENT_ERROR;
        }

        err = clock_gettime(CLOCK_MONOTONIC, &ts);
        if (err < 0) {
            printf("Error with gettimeofday! (%i)\n", err);
            return LIBBPF_PERF_EVENT_ERROR;
        }

        h.ts.tv_sec  = ts.tv_sec;
        h.ts.tv_usec = ts.tv_nsec / NANOSECS_PER_USEC;

        if (verbose) {
            printf("pkt len: %-5d bytes. hdr: ", e->pkt_len);
            for (i = 0; i < e->pkt_len; i++)
                printf("%02x ", e->pkt_data[i]);
            printf("\n");
        }

        pcap_dump((u_char *) pdumper, &h, e->pkt_data);
        pcap_pkts++;
        return LIBBPF_PERF_EVENT_CONT;
    }

这个函数将被许多线程调用,我希望 pcap_dump 调用由一个不同的线程执行。

【问题讨论】:

  • 这太宽泛了.. 完全取决于您的程序的体系结构以及它需要做什么。每当您有多个线程访问相同的数据时,这些访问都需要同步,否则您将遇到竞争条件。
  • 我已经编辑了这个问题,增加了更多的特异性,包括一个指向相关代码的链接。

标签: c linux multithreading io pthreads


【解决方案1】:

是的,这是一种避免延迟的常用方法,因为磁盘足够快以处理平均数据速率,但偶尔会出现数据峰值、磁盘缓存写入、目录更新等导致间歇性数据丢失的情况。

您需要一个生产者-消费者队列。这样的类或代码/结构,使用 condvars 或信号量,很容易在 SO 或网络上的其他地方找到。队列只需要对指针进行排队即可。

不要使用宽队列来排队批量数据。一旦从 [wherever] 读取它,就将其读入一个 malloced 缓冲区/结构,该缓冲区/结构具有数据、路径、命令以及写入线程可能需要执行写入的任何其他内容。将指向写入线程的结构指针排队。在写线程中,循环 P-C 队列弹出,获取指针,执行写操作,(或任何 struct 命令字段的命令),如果没有错误,则释放 struct。如果出现问题,您可以将错误消息加载到结构的某个字段中,然后将其再次排队到某个错误记录线程,将其存储在队列中以便稍后再试,无论您想要什么,真的。

这样,您可以将应用的其余部分与那些不可避免的、偶尔出现的磁盘延迟隔离开来。这对于高延迟磁盘非常重要,例如。网络上的那些。它还使内务操作变得更加容易,例如,一些小时计时器可以将一个结构排队,其命令字段指示线程打开文件名中带有日期时间戳的新文件,因此以后更容易跟踪数据而无需涉足一个庞大的文件:) 这样的操作,没有队列和写入线程,肯定会给你的应用程序造成巨大的延迟:(

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-22
    • 2020-09-21
    • 1970-01-01
    • 2021-07-11
    • 1970-01-01
    • 2014-10-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多