none
If task is not completed in certain time, stop the task and release its resources(not working for me) RRS feed

  • Question

  • Hello, I have a task and if the task does not completes until 4 seconds I want to open a file used by a task and dispose its stream, while trying to dispose its stream, I am getting an exception thrown which means the file is still not being released. I have got this code so far: 

    Task task= Task.Run(() =>
    {
    dssPut_Command("Compile " + "abc.dss");

    if (ct.IsCancellationRequested)
    ct.ThrowIfCancellationRequested();
    }, ct);
    tokenSource2.Cancel();
    try
    {
    if (!task.Wait(TimeSpan.FromSeconds(4)))
    {
    var sr = new StreamReader(abc.dss");
    Debug.WriteLine("error with the file.");
    sr.ReadToEnd();
    sr.Dispose();//getting an exception thrown in this part

    //stream is still not close/disposed }

    }
    catch (AggregateException ae)
    {
    Console.WriteLine("Task cancelled exception detected", ae.Message);


    }
    finally
    {
    tokenSource2.Dispose();


    }

    Monday, October 28, 2019 9:42 PM

All replies

  • Hi SarbeshB, 

    Thank you for posting here.

    Do you want to cancel the Task if the task does not complete until 4 seconds?

    If so, I make an example on my side, and you can refer to and modify it.

            static void Main(string[] args)
            {
                var tokenSource = new CancellationTokenSource();
                var token = tokenSource.Token;
    
                Task task = Task.Run(() =>
                {
                    for (int i = 0; i < 10; i++)
                    {
                        Thread.Sleep(1000);
                        Console.WriteLine(i);
                        if (token.IsCancellationRequested)
                        {
                            Console.WriteLine("cancel");
                            break;
                            //token.ThrowIfCancellationRequested();
                        }
                    }             
                }, token);
                try
                {
                    if (!task.Wait(TimeSpan.FromSeconds(4)))
                    {
                        tokenSource.Cancel();                 
                    }
                    // Wait 1 seconds for the task to complete
                    Thread.Sleep(1000);
                    Console.WriteLine("do your work");
                }
                catch (Exception ae)
                {
                    Console.WriteLine(ae.Message);
                }
                finally
                {
                    tokenSource.Dispose();
                }
                Console.ReadLine();
            }

    Result:

    Hope it could be helpful.

    Besides, if I have any misunderstanding, please provide more information about your problem and some code about ‘dssPut_Command("Compile " + "abc.dss")’.

    Best Regards,

    Xingyu Zhao



    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Tuesday, October 29, 2019 7:18 AM
    Moderator
  • Hello Xingyu, 

    Thank you for your answer. I tried implementing that way but still I am not being able to dispose the stream. I am having this exception:  EndOfStream = 'sr.EndOfStream' threw an exception of type 'System.ObjectDisposedException'. The reason I wanted to dispose the stream is, dssPut_Command, takes in a input file  and if the file has an error it keeps on sticking to that file and will not release the file, I wanted to delete the file. It says the file is being used by another process. Things I have tried so far is: 

    1. Killing the process, it works but the thing is this process is IIS process so I should not be killing that process.

    2. Deleting the specific thread, I did try that but it keeps on taking me to the catch blocks and does not release the file, further I came to know that Thread.Abort() may not release the resources associated with it. 

    What I am trying now is to open the file and delete it. For that I am creating a task and if it does completes for 4 seconds, I want to open the file( which I am being able to open). and dispose the stream. I believe if the stream can be disposed than I should be able to delete the file too. But while disposing the stream I keep on getting the same exception thrown which I think is file is still not being released. 

    Thanks  

    Unfortunately, I do not have the implementation of dss_Put Command, it is coming from DLL Library. 

    Tuesday, October 29, 2019 1:46 PM
  • Task task= Task.Run(() =>
    {
    Thread.Sleep(1000);
    dssPut_Command("Compile " + "abc.dss");//abc.dss has an error with it.

    if (ct.IsCancellationRequested)
    {
    Console.WriteLine("cancel");


    //ct.ThrowIfCancellationRequested();
    }

    }, ct);

    try
    {
    if (!task.Wait(TimeSpan.FromSeconds(4)))
    {
    tokenSource2.Cancel();




    }
    Thread.Sleep(1000);
    var sr = new StreamReader("abc.dss");
    Debug.WriteLine("error with the file. please regenerate the file and try again");
    sr.ReadToEnd();
    sr.Dispose();
    }



    catch (AggregateException ae)
    {
    Console.WriteLine("Task cancelled exception detected", ae.Message);


    }
    finally
    {
    tokenSource2.Dispose();


    }
    Tuesday, October 29, 2019 2:01 PM
  • This is a continuation of the same thread as discussed here. As discussed there you cannot simply "kill" a file just because you want to "cancel" a thread that uses it. It isn't going to work. You were given suggestions in the other thread. Did you try them at all or are you fixated on trying to get this idea that everyone says won't work working?

    As before you are completely fixated on the wrong problem. Calling `new StreamReader` opens up a brand new handle to that file. Reading that stream and closing it closes the handle you have. It has absolutely no impact on any other handle being managed by anybody else. You don't have access to those handles and cannot do anything with them. That entire stream logic you have does absolutely nothing. Your `dssput_Command` still has its own handle to the file that you don't have access to.


    Michael Taylor http://www.michaeltaylorp3.net

    Tuesday, October 29, 2019 2:02 PM
    Moderator
  • Hello CoolDadTx, 

    I have tried that too. There it says to try using and do something, it says even by doing something it will close the file. I have tried that , I is already implemented in my EngineManager, even I have added the dispose for every stream. That did not work in releasing the file. It makes sense with your answer that I will create a new handle, I will avoid using it. But as we discussed previously,  it is not helping me. 

    Thanks 

    Tuesday, October 29, 2019 2:23 PM
  • Also, I am not going through the deleting threads or process approach, I wanted to but since it won't work so I am not going through that way. 

    Also, the using part was already implemented in the engine manager I was working with , it was implemented in this way:

    path = System.IO.Path.Combine(path1, "abc.dss");

    using (StreamWriter sw = File.CreateText(path)){
    foreach (DataRow item in Tables[0].Rows)
    {
    Do something;}

    w.WriteLine(sb.ToString());

    sw.Dispose();

    }

    This did not help. 

    Tuesday, October 29, 2019 2:59 PM
  • Is there a way to delete the existing file handle? In the same code, if time exceeds more than 4 seconds , I want to delete the file handle and go ahead so that it will allow me to delete the file?
    Tuesday, October 29, 2019 3:09 PM
  • Again, the entire context of the discussion you've been having with people is that you have the file handle (via a stream or whatever). In that case disposing of the object will work. But as you mentioned in the other thread you don't have the file handle. You are calling your `dssPut_Command` function does the file work. Since you don't directly have control over the file no amount of "disposing" is going to help here. Unless I misunderstand what you said.

    The only way you can "dispose" of the file is if you, as in your code, creates it. If you don't create it then you cannot clean it up. Perhaps you've mentioned this before but where is `dssPut_Command` defined? Is this your function or a third party library? If it is yours then post the code.

    As for deleting the file, you cannot as you don't own it. As I mentioned in the other post there are workarounds but it completely depends upon the implementation of that `dssPut_Command`. I'll await your respond to identify the possible solutions.


    Michael Taylor http://www.michaeltaylorp3.net

    Tuesday, October 29, 2019 3:25 PM
    Moderator
  • CoolDadTx I completely understood what you said but it is a third party library. I am not being able to find the implementation of dssPut_Command. I just have it called in the code I am working with. I have tried to get the implementation of it but I believe it is more a third party. All I have is a documentation that says 

    Text Interface
    This interface can be used to send commands to the text interface of OpenDSS (DSS.Text). The structure of the interface is as follows:
    CStr DSSPut_Command(CStr Command);
    This interface returns a string pointer (ANSI) with the result of the command sent, the variable “Command” is used as input to send an OpenDSS command to the Text interface of OpenDSS.

    Nothing more than this. 

    https://sourceforge.net/p/electricdss/discussion/beginners/thread/be4d4bc5/3dc9/attachment/OpenDSS_Direct_DLL.pdf

    Tuesday, October 29, 2019 3:32 PM
  • http://svn.code.sf.net/p/electricdss/code/trunk/Distrib/Doc/OpenDSS_Direct_DLL.pdf

    CoolDadTx, here is the documentation for DSSPut_Command and about the DLL library too. 

    • Edited by SarbeshB Tuesday, October 29, 2019 3:55 PM
    Tuesday, October 29, 2019 3:54 PM
  • Based upon that link the library is written in Delphi and has a COM interface. I don't see this `DssPut_Command` that you're calling though so I cannot see the implementation. However someone has a .NET wrapper around this library. Can you look to see if it has the functionality you need?

    It might resolve your issue but most likely it is going to have the same issues. But looking at the wrapper API it seems like you could make the calls directly rather than passing in a file. I don't understand DSS but it looks like you're trying to compile a .DSS file. If that is true then I'm going to go back to what I originally recommended, use a separate process. Put the logic to compile a .DSS file into a standalone command line tool (if the DSS library doesn't already have it). Then use Process.Start to call that. If the process doesn't complete in the time you want then kill the process which will release the file. This is basically how VS compiles you're code and it works really well.


    Michael Taylor http://www.michaeltaylorp3.net

    Tuesday, October 29, 2019 4:11 PM
    Moderator
  • Yes, you are right I am trying to compile .dss file, I have no clue on how it implements but based on other files it does perform its action if there are no errors. I will try the way you said about putting it into a standalone command line tool. ( I have never worked with these kind of things before). I will try it and let you know what works.
    Tuesday, October 29, 2019 4:25 PM
  • Hello CoolDadTx, 

    I tried going on your recommendation, I am not sure if you mean to implement the compile command in  a separate process without using the dssPut_Command, in this case we are able to delete the file but even if the file has an error it process the file. Before, using dssPut_Command it would not process the file if there was an error. I am not sure if you meant this or may be I misunderstood what you are trying to say. 

    Here is the thing I have implemented:

    System.Diagnostics.Process process = new System.Diagnostics.Process();

    System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();

    startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;

    startInfo.FileName = "cmd.exe";

    Task task = Task.Run(() =>

    {process.StartInfo = startInfo;

    startInfo.Arguments = "Compile " +  "abc.dss";

    process.Start();

     if (ct.IsCancellationRequested)

     {

     Console.WriteLine("cancel");

    //ct.ThrowIfCancellationRequested();

    }}, ct);

    tokenSource2.Cancel();

      try

          {

            Thread.Sleep(1000);

            task.Wait(TimeSpan.FromSeconds(5));

                                            

              if (!task.IsCompleted)

               {

                 process.Kill();

                 return false;

                }

               else

             Console.WriteLine("Task ran to completion");

    }}

    So, instead of using dssPut_Command , I have used startInfo.Arguments = "Compile " +  "abc.dss";

    • Edited by SarbeshB Wednesday, October 30, 2019 1:38 PM
    Wednesday, October 30, 2019 1:36 PM
  • I have no idea what dssPut_Command does so I assume you need to run it. So create a new console application project in your solution. In that new project have it accept a filename as a command line argument. You can add other arguments as needed. Then inside that process have it call the dssPut_Command with the appropriate file. You've now wrapped the compile command into an EXE you can call.

    In your main project (where you got the posted code from) modify it to call your EXE instead of dssPut_Command. Then use Process.WaitForExit with a timeout to wait for it to finish, if you want to wait a fixed amount of time. If it doesn't complete then terminate the process.


    Michael Taylor http://www.michaeltaylorp3.net

    Wednesday, October 30, 2019 2:02 PM
    Moderator
  • I do not know if this is causing the issue, but Wait will synchronously block until the task completes. So the current thread is blocked waiting for the task to complete. As a general rule, you should use "async all the way down"; that is, don't block on async code. Thread.Sleep is another blocking call.

    Also, why are you explicitly calling Dispose Just wrap it in a using statement and let the GC do its job.

    using (var sr = new StreamReader("YOUR FILE HERE"))
    {
       var line = sr.ReadToEnd();
    }



    william xifaras

    Wednesday, October 30, 2019 2:15 PM