Need to confirm your design: Need to wait for 4 secs to close the socket connection


#1

void InterprocessConnection::disconnect()
{
thread->signalThreadShouldExit();

{
    const ScopedLock sl (pipeAndSocketLock);
    if (socket != nullptr)  socket->close();
    if (pipe != nullptr)    pipe->close();
}
**thread->stopThread (4000);**
deletePipeAndSocket();
connectionLostInt();

}

Why we need to wait 4 secs to disconnect a connection?

I had a bug, when i close alot connection, whole the plugin and the DAWs hang.
=> Then i found the issue.

Should we make that value by the default value of disconnect function ?


#2

That line doesn’t mean wait for 4000msecs, but stop the thread and give it 4000msecs time to shutdown. If it is still running, kill it.

If the InterprocessConnection is working normally, stopThread will return in a couple of msecs (I use that class, and it does for me).

I guess, if you have there problems, it might hang still trying to connect:

If you follow the code, there are “if threadSHouldExit()” all over the place, so once stopThread is called, I see no reason why it should not stop immediately…

But another thing to check, do your callbacks return immediately?
And do you use callbacks from messageThread (the default)? That way the callbacks can’t delay the disconnect…

I think killing the timer sooner should be the last resort…


#3

BTW: I took the liberty to move the thread to General JUCE discussion, because the category “Site feedback” talks about the website, so it might get lost there…
I hope you don’t mind.


#4

Ok thanks,

Please see the thread->stopThread (4000) function:

bool Thread::stopThread (const int timeOutMilliseconds)
{
// agh! You can’t stop the thread that’s calling this method! How on earth
// would that work??
jassert (getCurrentThreadId() != getThreadId());

const ScopedLock sl (startStopLock);
if (isThreadRunning())
{
    **signalThreadShouldExit();**
    notify();
    if (timeOutMilliseconds != 0)
        waitForThreadToExit (timeOutMilliseconds);
    if (isThreadRunning())
    {
        // very bad karma if this point is reached, as there are bound to be
        // locks and events left in silly states when a thread is killed by force..
        jassertfalse;
        Logger::writeToLog ("!! killing thread by force !!");
        killThread();
        threadHandle = nullptr;
        threadId = 0;
        return false;
    }
}
return true;

}

Please focus on this function:

waitForThreadToExit (timeOutMilliseconds);

bool Thread::waitForThreadToExit (const int timeOutMilliseconds) const
{
// Doh! So how exactly do you expect this thread to wait for itself to stop??
jassert (getThreadId() != getCurrentThreadId() || getCurrentThreadId() == 0);

const uint32 timeoutEnd = Time::getMillisecondCounter() + (uint32) timeOutMilliseconds;
while (isThreadRunning())
{
    if (timeOutMilliseconds >= 0 && Time::getMillisecondCounter() > timeoutEnd)
        return false;
    sleep (2);
}
return true;

}

return true;

}

Why it makes the main thread loop and waiting for 4000 mili sec.

When i change on your frame work to 10 milisecond.
It works very well.

Because my plugin have to open connect to others up to 50 plugin instances.

GIve me some explaination.
Should it be fixed ?


#5

You’ve signaled to the Thread to Exit with signalThreadShouldExit()

That means the Thread may be doing some work but it’ll be flagged to exit as soon as possible…

While the Thread is still working and hasn’t exited you’ve given it the stopThread() where it’ll wait until the Thread Exits because of the previous call… or stopThread() times out… in which case it’ll force quit the Thread… so the worse case scenario is that it’ll take 4000 ms and force quit the Thread which you’d prefer not to happen – but SignalThreadShouldExit() should cause the Thread to quit fairly quickly if the Thread is checking for the flag at a high enough rate.

The question isn’t about the stopThread()… it should be more about why isn’t the Thread exiting when you signal it to… or if it is… why is it taking so long

Thread::signalThreadShouldExit()

This is the relevant code to check why it’s not exiting:

void InterprocessConnection::runThread()
{
    while (! thread->threadShouldExit())
    {
        if (socket != nullptr)
        {
            const int ready = socket->waitUntilReady (true, 0);

            if (ready < 0)
            {
                deletePipeAndSocket();
                connectionLostInt();
                break;
            }

            if (ready == 0)
            {
                thread->wait (1);
                continue;
            }
        }
        else if (pipe != nullptr)
        {
            if (! pipe->isOpen())
            {
                deletePipeAndSocket();
                connectionLostInt();
                break;
            }
        }
        else
        {
            break;
        }

        if (thread->threadShouldExit() || ! readNextMessageInt())
            break;
    }
}

Rail


#6

That’s really the worst possible thing you could do! Force-killing the thread will leave all kinds of mutexes and other things in an undefined state, please never do that!

Like Rail suggested, the thing to look at is why InterprocessConnection isn’t quitting, which is maybe because of some kind of deadlock in your code?

If you have many plugins that need to communicate, then you probably don’t need to use InterprocessConnection, since they’ll generally all share the same memory space and you can just call methods to talk between them. But if you do need to call across to another process, the most efficient thing to do would be to create one single, shared InterprocessConnection object for all the plugins to use, perhaps with a SharedResourcePointer.


#7

…and one other thing to mention: When you changed the timeout and were killing your threads, you should have hit this assertion:

        // very bad karma if this point is reached, as there are bound to be
        // locks and events left in silly states when a thread is killed by force..
        jassertfalse;
        Logger::writeToLog ("!! killing thread by force !!");

You shouldn’t ignore that kind of warning. Or if you didn’t see it because you’re running without assertions, you really should enable them in your debug build so that we can warn when you do something silly!


#8

Ok i ll record the video to you.

This issue occurs when i change another preset of Pro tool only.

I open a new preset on Pro Tool.
I put a lot instance of my plugin.

I close one of them that works very well no hang.
But the issue only occurs when i change to another preset of Pro Tool.

It hands a bit then Pro Tool continue working(loading new preset.).

It hangs how long depend on how much instance i load.

I think this is an issue of your framework. I ll record video and show u.


#9

No, please don’t record a video, or tell us about what you’re doing when it happens. None of that info is helpful.

If something in your code is preventing the InterprocessLock thread from stopping as it should, then the only way to figure out what’s going on is for you to stop it your debugger, and look at what the threads are doing when this happens. That way you can figure out whether it’s a bug in your code or ours.


#10

Ok man. Thanks I ll check that and tell u later


#11

You may want to read this thread to see if it’ll help you.

Rail