Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/138.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
TIdTCPServer上下文上的应用程序挂起->;锁名单() 我在C++ Builder XE2中开发了所谓的“Pull”应用程序,它使用2个内置的DYY组件——TeTCPPoCube和TyTcPyver。TIdTCPClient用于接收来自一个源的数据,形成字符串消息,而不是使用TIdTCPClient将此字符串消息发送到所有应用程序客户端。对于数据重传,我使用下一个函数(idEventsServerSocket是TIdTCPSever组件):_C++_Deadlock_Indy10 - Fatal编程技术网

TIdTCPServer上下文上的应用程序挂起->;锁名单() 我在C++ Builder XE2中开发了所谓的“Pull”应用程序,它使用2个内置的DYY组件——TeTCPPoCube和TyTcPyver。TIdTCPClient用于接收来自一个源的数据,形成字符串消息,而不是使用TIdTCPClient将此字符串消息发送到所有应用程序客户端。对于数据重传,我使用下一个函数(idEventsServerSocket是TIdTCPSever组件):

TIdTCPServer上下文上的应用程序挂起->;锁名单() 我在C++ Builder XE2中开发了所谓的“Pull”应用程序,它使用2个内置的DYY组件——TeTCPPoCube和TyTcPyver。TIdTCPClient用于接收来自一个源的数据,形成字符串消息,而不是使用TIdTCPClient将此字符串消息发送到所有应用程序客户端。对于数据重传,我使用下一个函数(idEventsServerSocket是TIdTCPSever组件):,c++,deadlock,indy10,C++,Deadlock,Indy10,正在导致应用程序挂起。当函数向所有客户机发送数据时(比如说,每10-50毫秒调用一次),通常不会出现这种情况。客户端连接的数量从30到50不等。 我需要知道的是,有没有办法避免这种僵局?我有没有什么支票(比如TRYERCRiticalSection)? 我还想承认,Remy的解决方案没有帮助。LockList()需要在try块之外 上下文列表在内部使用关键部分,因此将此代码包装到您自己的关键部分是多余的 LockList()可以阻止的唯一方法是,如果另一个线程已经获得了锁,但没有释放它,这可能是

正在导致应用程序挂起。当函数向所有客户机发送数据时(比如说,每10-50毫秒调用一次),通常不会出现这种情况。客户端连接的数量从30到50不等。 我需要知道的是,有没有办法避免这种僵局?我有没有什么支票(比如TRYERCRiticalSection)? 我还想承认,Remy的解决方案没有帮助。

LockList()
需要在
try
块之外

上下文
列表在内部使用关键部分,因此将此代码包装到您自己的关键部分是多余的

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...
}
#包括
类TMyContext:public TIdServerContext
{
公众:
TIDSetreadSafeStringList*队列;
bool拥有msgsinqueue;
__fastcall TMyContext(TIdTCPConnection*A连接,TIDShrain*AYarn,TIdContextThreadList*AList=NULL)
:TIdServerContext(连接、AYarn、列表)
{
队列=新的TIdThreadSafeStringList;
HasMsgsInQueue=false;
}
__快速调用TMyContext()
{
删除队列;
}
};
__fastcall TfrmMainWindow::TfrmMainWindow(TComponent*Owner)
:t表格(所有者)
{
//在激活服务器之前设置此选项
idEventsServerSocket->ContextClass=\uu classid(TMyContext);
}
void TfrmMainWindow::SendDataToAllClient(常量字符串和消息)
{
TList*ClientsList=idEventsServerSocket->context->LockList();
尝试
{
对于(int i=0;iCount;++i)
{
TMyContext*上下文=(TMyContext*)客户端列表->项目[i];
尝试
{
TStringList*Queue=Context->Queue->Lock();
尝试
{
队列->添加(消息);
Context->HasMsgsInQueue=true;
}
__最后
{
上下文->队列->解锁();
}
}
捕获(常量异常&)
{
}
}
}
__最后
{
idEventsServerSocket->context->UnlockList();
}
}
void\uu fastcall TfrmMainWindow::idEventsServerSocketExecute(TIdContext*AContext)
{
TMyContext*ctx=(TMyContext*)文本;
如果(ctx->HasMsgsInQueue)
{
TStringList*Msgs=NULL;
尝试
{
TStringList*Queue=ctx->Queue->Lock();
尝试
{
Msgs=新的TStringList;
Msgs->Assign(队列);
队列->清除();
ctx->HasMsgsInQueue=false;
}
__最后
{
ctx->队列->解锁();
}
AContext->Connection->IOHandler->Write(Msgs);
}
__最后
{
删除MSG;
}
}
if(AContext->Connection->IOHandler->InputBufferIsEmpty())
{
AContext->Connection->IOHandler->CheckForDataOnSource(100);
AContext->Connection->IOHandler->CheckForDisconnect();
if(AContext->Connection->IOHandler->InputBufferIsEmpty())
返回;
}
//根据需要处理入站数据。。。
}

非常感谢您为正确使用上下文打开我的眼睛,我没想到会有如此详细的代码。我有10.5.8.0 Indy版本,它没有定义TIdContextThreadList。我可以在TMyContext构造函数中使用System::Classes::TThreadList而不更改代码中的任何其他内容吗?还有一个问题。。。我的原始代码允许IMMIDATE重传(在我的情况下,1-2毫秒的延迟非常重要),使用您提供的代码,我将在检查输入缓冲区时获得延迟。在OnExecute事件之前,我只是读取客户机的数据,现在我甚至明白这可能是死锁的原因。CheckForDataSource中的参数是否可以从100更改为1或2而没有任何问题?是的,在早期版本中使用
TThreadList
(请参阅
IdContext.pas
中的
TIdContext
构造函数声明)。至于延迟,是的,您可以减少使用的超时。但是,如果您的
OnExecute
处理程序只需要读,不需要写,那么您就不需要使用我展示的方法。在一个线程中读取而在另一个线程中写入是安全的,无需同步对套接字的访问。我只是不建议在主UI线程中使用发送循环。被阻止的客户端将阻止整个循环,这就是我移动写操作的原因
ClientsList = idEventsServerSocket->Contexts->LockList();
#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...
}