我在C中创建了一个线程池。池中的每个线程执行完全相同的函数。几个生产线程使用相当标准的mutex/cond方法将新数据放入这个池的队列中。
新的数据总是相对较大的,必须执行的处理量可能需要相当长的一段时间。每当我看到这样的实现时,工作人员在复制所需数据或执行所请求的任务时锁定队列。在我的情况下,这些操作可能需要一段时间,在此期间,其他线程将被阻止访问队列。
我应该如何宣布一个特定的线程已经接受了一个任务,但是与该任务相关联的数据仍在使用?在队列中添加某种“in-process”标志并让工作线程在队列工作时解锁队列是否可行?
最佳答案
修改排队结构,使排队的只是一个指向要处理的数据的指针。
当一个线程需要抓取一个作业时,它抓取互斥锁,获取要执行的任务的下一个指针,可能抓取指针的队列内副本,或者以其他方式确保其他线程不会处理它正在处理的内容,然后释放互斥锁(或发出条件或其他信号)。对大块数据的访问是通过指针进行的;只有一个线程有指针;当指针完成时,它会进行清理,但在知道没有其他线程在处理相同的数据时,它会安全地运行。
因此,您可以通过不在队列中使用大块数据来解决这个问题—您使用小块数据,也就是指向大块数据的指针。
当前我的队列是指针队列。但是,在程序开始时,缓冲区的数量是有限的。如果我错了,请纠正我,但你的建议是,我应该根据需要使用producer threadsmalloc
内存,并在完成时让workersmalloc
内存?
我不是建议你让生产者使用free
而消费者使用malloc()
。
我的建议是,你要组织队列,这样就不存在生产者或消费者需要长时间锁定队列的问题。但是,如果您的队列已经是一个指针队列,我不理解您最初是如何遇到问题的。
可能要归结到术语上——这是造成混乱的主要原因。
我想说的是,有一个“等待消费的任务”队列。有时,该队列将为空;然后使用者线程将在“queue not empty”条件下等待,并且当生产者向队列中添加任务时,等待的使用者之一将被唤醒并接管新任务的运行。但消费者的第一步只是将任务从“等待消费”队列中移除。
队列上的信息必须足以标识需要执行的操作—这可能只是指向“任务描述”的指针,其中包含指向要操作的数据存储位置的进一步指针。从队列中删除“任务描述”应该(必须)是一个快速、简单的操作(受互斥锁和条件保护)。一个给定的任务描述不能被多个线程同时访问它所指向的数据不能被其他线程访问(通常)。如果在线程之间共享数据,则必须像往常一样协调对该共享数据的并发访问。
但是,关键的设计点是,使用者线程在处理队列时花费最少的时间阻塞其他使用者线程或生产者线程。它获得对队列的访问权,删除队列上的第一个项,并释放对队列的访问权。然后,它继续处理需要完成的任务——不受生产者或其他消费者的干扰。
同样,生产者线程准备任务描述并确保使用相关的(预分配的)缓冲区,等等——小心地处理缓冲区的获取,等等。但是当任务描述准备好时,生产者花费很短的时间获取对队列的访问,将任务描述添加到队列中,正在释放对队列的访问,发出“队列不为空”条件的信号。