TIdTCPServer Contexts->LockList() 上的应用程序挂断
Application hangup on TIdTCPServer Contexts->LockList()
我正在c++ Builder XE2中开发所谓的"feeder"应用程序,它使用2个内置的Indy组件- TIdTCPClient和TIdTCPSever。TIdTCPClient用于从一个源接收数据,形成字符串消息,然后使用tidtcpserver将此字符串消息发送到所有客户端应用程序。对于数据重新翻译,我使用下一个函数(idEventsServerSocket是TIdTCPSever组件):
void TfrmMainWindow::SendDataToAllClients(String msg) {
TList *ClientsList;
try
{
ClientsList = idEventsServerSocket->Contexts->LockList();
for (int i = 0; i < ClientsList->Count; i++) {
TIdContext *Context = (TIdContext*)ClientsList->Items[i];
bool connected = false;
try {
connected = Context->Connection->Connected();
}
catch (Exception&e) {
continue;
}
if (!connected)
continue;
try {
Context->Connection->IOHandler->WriteLn(msg);
Context->Connection->IOHandler->WriteBufferFlush();
}
catch (Exception&e) {
}
}
}
__finally
{
idEventsServerSocket->Contexts->UnlockList();
}
}
我还想注意到这个函数包含在EnterCriticalSection中…leaveccriticalsection代码段,因此应该保证在函数未执行之前不会出现对该函数代码的新入口。对于idEventsServerSocket, OnException和OnListenException处理程序被定义并包含空代码。
所以问题是:有时候
这行ClientsList = idEventsServerSocket->Contexts->LockList();
导致应用程序挂起。当它发生时没有一般的规律,但看起来它发生在函数SendDataToAllClients非常频繁地被调用时(例如每10 - 50毫秒一次)。客户端连接数为30 ~ 50。我想知道的是,有没有办法避免这种僵局?我有任何类型的检查(如TryEnterCriticalSection) ?我也想承认,Remy的解决方案从Delphi: TThreadList有时锁程序没有帮助。
LockList()
需要在try
块之外。
Contexts
列表在内部使用了一个临界区,所以在你自己的临界区中包装这些代码是多余的。
LockList()
可以阻塞的唯一方式是如果另一个线程已经获得了锁并且没有释放它,或者因为它正在忙着使用列表,或者更有可能它崩溃并且没有释放锁。
在此代码中不要调用Connected()
或WriteBufferFlush()
。您没有使用写缓冲,并且从TIdTCPServer
事件之外调用Connected()
将在连接的InpuBuffer
上导致竞争条件,干扰管理该连接的服务器线程,这可能导致崩溃、死锁、入站数据损坏等。只需单独调用Write()
,并让它在套接字已断开连接时抛出异常。
你所展示的是用TIdTCPServer
实现TCP广播的一种不安全的方式。您应该实现每个客户机线程安全的出站队列,并让OnExecute
事件处理实际的写入:
#include <IdThreadSafe.hpp>
class TMyContext : public TIdServerContext
{
public:
TIdThreadSafeStringList *Queue;
bool HasMsgsInQueue;
__fastcall TMyContext(TIdTCPConnection *AConnection, TIdYarn *AYarn, TIdContextThreadList *AList = NULL)
: TIdServerContext(AConnection, AYarn, AList)
{
Queue = new TIdThreadSafeStringList;
HasMsgsInQueue = false;
}
__fastcall TMyContext()
{
delete Queue;
}
};
__fastcall TfrmMainWindow::TfrmMainWindow(TComponent *Owner)
: TForm(Owner)
{
// set this before activating the server
idEventsServerSocket->ContextClass = __classid(TMyContext);
}
void TfrmMainWindow::SendDataToAllClients(const String &msg)
{
TList *ClientsList = idEventsServerSocket->Contexts->LockList();
try
{
for (int i = 0; i < ClientsList->Count; ++i)
{
TMyContext *Context = (TMyContext*) ClientsList->Items[i];
try
{
TStringList *Queue = Context->Queue->Lock();
try
{
Queue->Add(msg);
Context->HasMsgsInQueue = true;
}
__finally
{
Context->Queue->Unlock();
}
}
catch (const Exception &)
{
}
}
}
__finally
{
idEventsServerSocket->Contexts->UnlockList();
}
}
void __fastcall TfrmMainWindow::idEventsServerSocketExecute(TIdContext *AContext)
{
TMyContext *ctx = (TMyContext*) AContext;
if (ctx->HasMsgsInQueue)
{
TStringList *Msgs = NULL;
try
{
TStringList *Queue = ctx->Queue->Lock();
try
{
Msgs = new TStringList;
Msgs->Assign(Queue);
Queue->Clear();
ctx->HasMsgsInQueue = false;
}
__finally
{
ctx->Queue->Unlock();
}
AContext->Connection->IOHandler->Write(Msgs);
}
__finally
{
delete Msgs;
}
}
if (AContext->Connection->IOHandler->InputBufferIsEmpty())
{
AContext->Connection->IOHandler->CheckForDataOnSource(100);
AContext->Connection->IOHandler->CheckForDisconnect();
if (AContext->Connection->IOHandler->InputBufferIsEmpty())
return;
}
// handle inbound data as needed...
}
- 试图在visual studio上用C++创建一个桌面应用程序
- FFmpeg:制作一个应用程序比直接使用ffmepg更好吗
- 在C应用程序中运行C++(带有STL)函数
- 使用VerQueryValue检索应用程序的文件描述
- Qt C++静态thread_local QNetworkAccessManager是线程应用程序的好选择吗
- 使用调试/崩溃报告将应用程序部署到客户端
- C++控制台应用程序阻止退出
- 码头化的C++应用程序是否向后兼容早期的内核版本
- 将应用程序从32位移植到64位时出现问题
- 如何改变c++应用程序的视觉效果
- WM_CTLCOLORSTATIC从未在WIN32应用程序中触发
- PC中的程序和PHONE中的本机描述应用程序之间的数据连接
- 应用程序崩溃并显示"symbol _ZdlPvm, version Qt_5 not defined in file libQt5Core.so.5 with link time reference"
- 示例外壳应用程序显示的 V8 "segmentation fault (core dumped)"错误
- phytec phyBOARD iMX-6在从闪存而不是SD卡运行qt5 opengles应用程序时表现不佳(FPS减半
- 为什么导入Mixed native/CLR lib.dll的本机C++应用程序没有在Mixed lib.dll中的外部变
- 如何从Windows应用程序输出到标准?
- C++应用程序 MySQL odbc 数据库连接错误:在引发"otl_tmpl_exception<>"实例后终止调用
- 如何在 64 位 vb.net Windows 应用程序中引用 32 位 dll
- TIdTCPServer Contexts->LockList() 上的应用程序挂断