TtT23
TtT23

Reputation: 7030

Need ideas on implementing the cancellation on this background worker

I have a button which initiates a connection between the program and a machine known as DDC. To prevent the UI thread from being locked while the connection is being established, I naturally create a backgroundworker to handle the job.

The problem is this: In the event where the client doesn't get any response from the DDC, the client has to wait for 30 seconds before giving a timeout. More precisely speaking, the thread halts executing on the line "GetLogicStatusListResponse result = ddcdao.GetLogicStatusList();".

I'd like the user to be able to cancel the operation if a button has been clicked on the program, but as far as I know there is no way to abort backgroundworker and cancellation wouldn't really help me here since the thread is locked for 30 seconds before the code can even check if cancellationpending is true or not.

I would like to hear some ideas to properly implement the cancellation feature so that the user may start/stop the connection whenever he/she wishes to.

private void bwWorkerConnect_DoWork(object sender, DoWorkEventArgs e)
        {
            //Branch in only if the DDC returns a ping response
            if (DDCGlobal.DDCPingTest(ddc))
            {
                try
                {
                    //Creates an object of class which communicates with the engine
                    //Retrieves the object obtained through remoting (Engine) 
                    //and casts it to a ReqDDCLogicListResponse type (See CommonEngine)
                    DDCDAO ddcdao = new DDCDAO(DDCGlobal.ddcEngineIP, ddc.Ip);

                    //Request status list from DDC (TIMEOUT = 30 SECONDS)
                    GetLogicStatusListResponse result = ddcdao.GetLogicStatusList();
               ...
            if (bwWorkerConnect.CancellationPending)
            {
                e.Cancel = true;
            }



    public void LogicListLoad()
    {
        if (!bwWorkerConnect.IsBusy)
            bwWorkerConnect.RunWorkerAsync();
        else
        {
            MessageBox.Show(UIConstant.DDC_CONNECT_ALREADY_WARNING);
        }

    }

Upvotes: 0

Views: 130

Answers (1)

Alex
Alex

Reputation: 23310

Posting my comment as answer for future reference.

You can approach your issue with a second BackgroundWorker running alongside the first, which only polls a flag in the first one to verify its status: since he's independent, it doesn't have to "wait" and is free to kill the first worker in case it gets stuck.

This should be deadlock-free since the second worker does nothing more than a periodic "health check" of the first worker as long as the flag handling instructions are wrapped up in a lock.

Flow would look like this:

  • When you need a connection, fire up both workers
  • First worker proceeds to attempt the connection, sets a flag to notify the outer world its "connecting" status
  • Second worker might check the first worker status every second 30 times: if it never reads anything different from "connecting" it can proceed and kill the first worker. It might also react to user input and kill the first worker before time (ie. any user input cancels the second worker, which in turn can kill the first one before its own demise).
  • Flow end

Upvotes: 3

Related Questions