ALZ*_*ALZ 3 delphi messaging multithreading delphi-7
我正在研究小型监控应用程序,它将通过SNMP,TCP,ICMP与某些设备进行通信,其他线程必须执行一些计算.所有这些结果我必须在GUI(一些Forms或TabSheets)中输出.
我正在考虑下一个可能性:
Synchronize从每一个工作者线程: Synchronize,但仅限于GUI专用线程,或GUI上的Critical Section来显示消息. TTimer主要形式,它将定期检查(100-1000毫秒)共享缓冲区并消耗,而不是Windows消息传递.(它对消息传递有一些好处吗?)亲爱的专家,请解释什么是最佳实践或暴露的替代品的优缺点是什么.
更新:
作为想法:
//共享缓冲区+发送消息变量
LogEvent全局函数将从任何地方调用(也来自工作线程):
procedure LogEvent(S: String);
var
liEvent: IEventMsg;
begin
liEvent := TEventMsg.Create; //Interfaced object
with liEvent do
begin
Severity := llDebug;
EventType := 'General';
Source := 'Application';
Description := S;
end;
MainForm.AddEvent(liEvent); //Invoke main form directly
end;
Run Code Online (Sandbox Code Playgroud)
在主窗体中,事件ListView和共享部分(fEventList: TTInterfaceList已经是线程安全的)我们将:
procedure TMainForm.AddEvent(aEvt: IEventMsg);
begin
fEventList.Add(aEvt);
PostMessage(Self.Handle, WM_EVENT_ADDED, 0, 0);
end;
Run Code Online (Sandbox Code Playgroud)
消息处理程序
procedure WMEventAdded(var Message: TMessage); message WM_EVENT_ADDED;
...
procedure TMainForm.WMEventAdded(var Message: TMessage);
var
liEvt: IEventMsg;
ListItem: TListItem;
begin
fEventList.Lock;
try
while fEventList.Count > 0 do
begin
liEvt := IEventMsg(fEventList.First);
fEventList.Delete(0);
with lvEvents do //TListView
begin
ListItem := Items.Add;
ListItem.Caption := SeverityNames[liEvt.Severity];
ListItem.SubItems.Add(DateTimeToStr(now));
ListItem.SubItems.Add(liEvt.EventType);
ListItem.SubItems.Add(liEvt.Source);
ListItem.SubItems.Add(liEvt.Description);
end;
end;
finally
fEventList.UnLock;
end;
end;
Run Code Online (Sandbox Code Playgroud)
有什么坏事吗?主窗体在应用程序启动时分配ONCE,在应用程序退出时销毁.
这可能是最简单的实现方法,但正如其他人指出的那样会导致IO线程被阻塞.这可能/可能不是您的特定应用程序中的问题.
但是应该注意,还有其他原因可以避免阻塞.阻塞可以使性能分析变得有点棘手,因为它有效地增加了"赶紧等待"的例程所花费的时间.
这是一个很好的方法,有一些特殊的考虑因素.
如果您的数据非常小,PostMessage可以将其全部打包到消息的参数中,使其成为理想选择.
但是,由于您提到了共享缓冲区,因此您可能会获得更多数据.这是你必须要小心的地方.直观地使用"共享缓冲区"可以让您了解竞争条件(但我将在后面详细介绍).
更好的方法是创建消息对象并将对象的所有权传递给GUI.
PostMessage.PostMessage以确认它实际已发送,如果没有发送,您也可以销毁该对象.使用任何类型的单独的中间线程仍然需要类似的考虑因素来获取相关数据到新线程 - 然后仍然必须以某种方式传递给GUI.如果您的应用程序需要在更新GUI之前执行聚合和耗时的计算,这可能才有意义.与您不想阻止IO线程的方式相同,您不希望阻止GUI线程.
我前面提到了共享缓冲区的"直观思想",意思是:"不同的线程同时读写"; 让您面临竞争风险.如果在写入操作的中间开始读取数据,则可能会以不一致的状态读取数据.这些问题可能是调试的噩梦.
为了避免这些竞争条件,您需要依靠其他同步工具(如锁)来保护共享数据.锁定当然会让我们回到阻塞问题,尽管形式略好一些.这是因为您可以控制所需保护的粒度.
这确实比消息传递有一些好处:
只有在适用的情况下,才有办法改进共享数据的概念:某些情况允许您选择使用不可变数据结构.即:数据结构在创建后不会更改.(注意:前面提到的消息对象应该是不可变的.)这样做的好处是,您可以安全地读取数据(来自任意数量的线程),而无需任何同步原语 - 只要您可以保证数据不会更改.
| 归档时间: |
|
| 查看次数: |
2382 次 |
| 最近记录: |