【问题标题】:Fix maximum number of threads for a program using a Mutex or Semaphor使用 Mutex 或 Semaphor 修复程序的最大线程数
【发布时间】:2021-04-15 04:23:19
【问题描述】:

提醒一下,这个项目是针对一所学校的,我对 C 和多线程都很陌生。

我正在尝试使用多个线程对输入列表中的每对无序文件运行统计分析函数。我需要接受用户输入的运行线程数。

按照我目前设置程序的方式,我已经创建了一个结构数组,其中包含必须进行的每个比较的文件名,如下所示:

typedef struct JSD {
    float distance;
    char * name1;
    char * name2;
    int w_cnt;
};

我在想,与其创建一个单独的队列结构来保存所有比较的列表,我可以简单地遍历整个数组,为每个元素创建一个线程,然后将结果输出回数组。我的信念是,通过这种方法,我不必像保护队列那样保护数组结构,因为每个线程一次只能处理一个单一的元素。我知道线程创建是 CPU 密集型过程,但这对我来说目前并不是一个主要问题。

但是,如果在继续遍历我的数组时已经达到预定义的线程限制,我不确定如何防止额外的线程实例。我的想法是创建一个变量来跟踪当前正在运行的线程数,但该数字显然需要限制其访问以防止出现竞争条件。我想知道互斥体或信号量是否能够实现这一点。

其中任何一个都能够实现我想要做的事情吗?我对每一个都不是很熟悉,所以如果他们能提供任何关于设置的指导,我将不胜感激。或者我错了不需要保护我的阵列,我应该排队。 任何指导将不胜感激。

【问题讨论】:

    标签: c multithreading mutex semaphore


    【解决方案1】:

    执行此操作的简单方法是记录到目前为止您已启动的线程数,一旦您的计数达到(您的最大线程值),请在您创建的第一个线程上调用 pthread_join()pthread_join() 在该线程退出之前不会返回,因此您的主线程在第一个/最旧的线程完成之前不会继续(或启动任何更多子线程)。

    pthread_join() 返回后,您可以启动另一个线程,然后在您创建的第二个线程上调用 pthread_join(),然后启动另一个线程,然后在第三个线程上调用 pthread_join(),以此类推,直到您完成到达数组的末尾(此时您还应该在所有剩余线程上调用pthread_join(),以确保它们在您的程序退出之前全部运行完成)

    【讨论】:

    • 这个实现需要互斥体吗?我是否可以通过等待 pthread_join 递减来避免径流情况?
    • 此实现不需要互斥锁(好吧,pthread_join() 可能在内部某处使用互斥锁,但您不直接与它交互)。 phread_join() 只是阻止主线程以防止它在任何初始 N 线程完成其工作之前启动更多线程。它避免的唯一竞争条件是竞争条件(如果您从不调用 pthread_join())您的 main() 可能会返回(并因此导致整个进程退出)而某些子线程仍在执行,从而导致某些线程在他们完成之前被杀死。
    • 感谢@Jeremy 的帮助。尽管我对捕获特定线程仍然有些困惑。我初始化了一个用于保存多个线程的数组,但我不确定这是否与您建议的结构兼容。
    • @sbling 我假设您正在使用pthread_create() 或类似方法生成线程;如果是这样,那么pthread_create 的第一个参数是指向pthread_t 对象的指针,pthread_create() 将覆盖该对象以包含创建线程的唯一标识符。稍后,当您想等待该线程退出时,您需要将pthread_t 值作为第一个参数传递给pthread_join(),以告诉pthread_join() 您要等待哪个线程。 (存储该信息的一种简单方法是将pthread_t 成员值添加到数组的每个元素)
    【解决方案2】:

    您在这里描述的是 Thread Pool -- 将独立运行但具有最大实例数的工作人员。

    有几种方法。一种是在进程开始时创建定义数量的工作线程,并使用控制器将工作分配给工作线程,因为它们在池中可用,然后将完成的线程返回到就绪状态以接受未来的工作。

    我认为这是最灵活的方法,因为您可以独立于线程工作实现来构建、测试和监控控制器。如果工作性质发生变化,对控制器来说没什么大不了的。

    也没有真正的关键部分,因为线程状态(例如就绪、工作、完成)管理它,并且从控制器的角度来看是原子的。

    我什至对这种方法的效率更高不感兴趣——它只是更容易维护。

    【讨论】:

    • 我知道对于现实世界的应用程序,线程池将更容易使用。但是,我想知道在这种特殊情况下,一个简单的计数器是否就足够了,而无需像 Jeremy 提到的那样创建队列。
    • Jeremy 的建议是一个非常幼稚的线程池。
    猜你喜欢
    • 2018-10-15
    • 1970-01-01
    • 2010-09-13
    • 1970-01-01
    • 1970-01-01
    • 2016-05-10
    • 1970-01-01
    • 2021-01-31
    • 2011-04-20
    相关资源
    最近更新 更多