Delphi多线程 线程领取任务的问题(100分)

  • 主题发起人 主题发起人 AKFish
  • 开始时间 开始时间
A

AKFish

Unregistered / Unconfirmed
GUEST, unregistred user!
做了个线程池
希望由线程自行到线程池那里领取任务
于是在TThreadPool类中写了一个GetTask方法
线程调用这个方法获得任务
function TThreadPool.GetTask(TID: integer): boolean;
var
P: Pointer;
begin
P := FTasks.Pop();
//FTasks: TQueue;
是任务队列
FThreads[TID].SetTask(P);
Result := (P <> nil);
end;

其中SetTask是线程对象的方法
用于把对领取到的任务进行预处理
GetTask的返回值如果为false则触发timeout
一定时间后Free空闲的线程
现在的问题是,实际调试的时候,线程领取不到任务.添加断点调试发现,GetTask中的代码不会完全执行,一般只执行第一句.考虑到可能是同步的问题,就用了Synchronize,问题依旧.求问题原因及解决方法...
 
可以使用互斥对象试试
 
TQueue不支持多线程
 
尝试用了临界区
但是依然不行
代码只执行第一句
后面的都不执行
线程的Excute中的代码
只要执行到直接或间接调用GetTask的地方就不往下了
而且线程直接结束掉
 
你的思路是对的,
我用这种方法实现了很多程序,没问题的,错误的肯定是程序局部问题。
建议GetTask用synchronize方法来调用
 
GetTask用synchronize方法来调用 ,有啥好处啊?
synchronize占用不是主线程嘛
如果用于是计算的话可以不用synchronize吧
如果涉及到显示等,用synchronize这个比较好吧。
随便说说,请指正!
 
因为任务队列是多个线程公用的,一般放在主线程中,
因此,如果不加以同步处理,会发生访问冲突。
这些问题,我已经全部遇到过并解决了,所以,我认为楼主的思路是对的,就是代码局部的问题。
我用的是环型任务队列+多线程,用专门的GetTask给线程分配任务。
另外建议楼主注意线程的结束条件:
只有在terminated标志=True及分配不到新任务时,才结束线程,否则,一直
进行“分配任务+执行任务”的循环。
 
如果你把初始化、释放、线程环回、动态增加的代码都拿出来,也许大家会更有效的帮助你。
 
GetTask后再来一个SetTask就需要多考量N多N多的问题。实际上,既然线程对象在GetTask
里就能访问,线程对象就根本没有必要执行一个SetTask的方法,只要在线程对象领取任务
期间让线程对象进行低CPU消耗的 等待任务-查询标志-根据标志决定继续等待还是执行任务
就可以了(就是说,线程方法不要进入到其他线程方法中)。
比如SetTask函数中仅仅做二事,一:把任务信息复制给线程对象的某个私有成员,二:利
用事件标志标示任务已经取道。这里的关键是不要让线程对象中的线程方法直接去处理任
务数据,而是异步地通过事件标志,让线程对象中的方法脱离等待状态即可。
如果这样做了你还是没有达到目的,那么就不是方法问题了,而是你的线程结构代码存在问题了。
 
以下是我的这部分代码,请参考,其中GetOutMessage过程就相当于那个GetTask,
代码应该很清晰的:
//
// 分配同步消息的过程...
//
// 入口参数:
// 无
// 出口参数:
// m_MessageText=分配到的消息体
// m_remoteip=接收方IP地址
// m_remoteport=接收方端口
// m_NeedRetry=是否需要重发
//
procedure TOutThread.GetOutMessage;
begin
//
// 若队列空,分配失败...
if form1.OutQueueEmpty then
begin
m_messagetext:='';
m_remoteip:='0.0.0.0';
m_remoteport:=0;
exit;
end;
//
// 若队列不空,则消息出队列...
dec(form1.activeoutmessages);
{记数-1}
m_messagetext:=form1.outqueue[form1.outQueueFore].MessageText;
m_remoteip:=form1.outqueue[form1.outqueuefore].RemoteIp;
m_remoteport:=form1.outQueue[form1.outqueuefore].RemotePort;
//
// 修正队列参数...
form1.OutQueueFull:=false;
{消息队列不满}
inc(form1.Outqueuefore);
{头指针+1}
if form1.OutQueueFore>=form1.s_OutQueueSize then
{到顶部时,指针折回}
form1.OutQueueFore:=0;
if form1.OutQueueFore=form1.OutQueueRear then
form1.OutQueueEmpty:=true;
{若头指针追上尾指针时,队列为空}
end;

//
// 线程主程序...实现UDP消息的发送
procedure TOutThread.Execute;
var
tmpstr: string;
buffer: array [0..8192] of char;
i,j: integer;
begin
//
// 一直循环,直到Terminated...
while not terminateddo
begin
//
// 从消息队列获取消息...
synchronize(getOutMessage);
//
// 若分配不到消息,则挂起线程...
if m_messagetext='' then
begin
synchronize(SetNeedCheckQueue);
suspend;
continue;
end;
//
// 下面是任务处理...
......
end;
end;
 
TIdThreadManager这么好的池为什么不用?
我就用这个!
 
=_=
好吧
先谢谢大家了
我还是再重新写一遍
看看会不会出问题
反正代码没在这台机器上也没法改
以前也做过一些池子
这次主要是想做个有线程领取任务和池子分配任务两个模式,能执行通用任务的池子
 
synchronize(SetNeedCheckQueue);
在主线程中执行 会引起阻塞 若 触发频繁 出现假死
 
后退
顶部