4

I have the following code:

while (condition == true)
{
    //First part
    using (var stream = File.Create(audioPath))
    {
        using (WaveFileWriter writer = new WaveFileWriter(stream, waveFormat))
        {
            writer.Write(audioBytes.ToArray(), 0, audioBytes.ToArray().Length);
        }
    }
    //Second part
    using (Process.Start("cmd.exe", commands)) { };
    Thread.Sleep(1000);
}

The first part saves a byte array to an audio file, then the second part of my code runs a .cmd file that does some processing on the code. However, this above code returns the error

the process cannot access the file (audioPath) because it is being used by another process.

I have read some other answers and have encountered this problem before but always managed to solve it with a using statement.

Both parts run correcly independently (when the other part is commented out). I am running this on Windows Server 2016 if that has any affect. I have added permissions to the folder/file also and because they both work independently, I doubt it's a permissions issue.

Is it possible that the using statement is not disposing correctly?

Michał Turczyn
  • 32,028
  • 14
  • 47
  • 69
Harry Stuart
  • 1,781
  • 2
  • 24
  • 39
  • Note: `using` will *always* call `Dispose()` on block exit. – user2864740 Dec 20 '18 at 07:03
  • That’s what I thought. Not sure what could be causing the error then... – Harry Stuart Dec 20 '18 at 07:04
  • Could "commands" be running longer than the original `cmd.exe` process? Windows does not have such a tidy parent-child process relationship as *ix does. – user2864740 Dec 20 '18 at 07:05
  • `Is it possible that the using statement is not disposing correctly?` - Realistically, no. Is this the actual code you have, or is it a stripped down version for SO? There is surely something else amiss. (Could even be an antivirus thing; but I would first check the code) – Christian.K Dec 20 '18 at 07:06
  • would doing `writer.Close()` make a difference - i know i know, the using statement but might be worth a shot... – jazb Dec 20 '18 at 07:07
  • I have updated the code, essenitally this entireblock executes every ~1.5s considering the `.cmd` process takes ~0.5s. However, if the `using` statement that encapsulates the `Process` is working properly, I can't see why this would make a difference. – Harry Stuart Dec 20 '18 at 07:15

2 Answers2

2

Are you really generating files by the same name? audioPath doesn't seem to change.

while (condition == true)
{
    //First part
    using (var stream = File.Create(audioPath))
    {
        using (WaveFileWriter writer = new WaveFileWriter(stream, waveFormat))
        {
            writer.Write(audioBytes.ToArray(), 0, audioBytes.ToArray().Length);
        }
    }
    //Second part
    using (Process.Start("cmd.exe", commands)) { };
    Thread.Sleep(1000);
}

Consider the following:

  1. The auditPath is written.
  2. The cmd-command starts using it - you don't wait for it to finish.
  3. Since you don't wait for it to finish, the loop enters the next iteration and a new auditPath is written while the cmd-command already is using the "previous" one.

alternatively

  1. Before the cmd-command actually has started (but after the Process.Start() has already completed), the loop comes to the next iteration and opens a new "version" of auditPath, writing to it.
  2. The cmd-command finally starts to access the file and you get the seen error.

All in all you have a race condition here. Make sure you wait for Process to finish, e.g.

using (var proc = Process.Start(...)) 
{
   proc.WaitForExit();
   // You might want to check `proc.ExitCode`, etc.
}

before running the next loop-cycle.

Key take-away: Process.Start() is not synchronous. If you need to wait for the launched command to finish, you need to explicitly do it, otherwise it continues to run in the background and might interfere with your other logic - as it currently does.

Christian.K
  • 47,778
  • 10
  • 99
  • 143
  • Firstly, yes. I create an audio file, process it, then replace that audio file with a new one and process the new file etc. – Harry Stuart Dec 20 '18 at 07:21
  • Exactly the problem I describe. – Christian.K Dec 20 '18 at 07:23
  • I see. In response to your first idea, do you mean creating the second audio file with a different path? I guess this would solve the problem, but I don't just want an endless amount of files. Maybe begine replacing the former files after a certain amount of time? – Harry Stuart Dec 20 '18 at 07:24
  • No, don't change your logic if you don't have to. Just wait for the command you launch to finish as I indicated at the end of the answer. Oh and if you have the `Thread.Sleep(1000)` in there solely as means to wait for the command to finish - drop it. It doesn't work use `proc.WaitForExit()`. – Christian.K Dec 20 '18 at 07:25
  • Apologies, I was getting a bit ahead of myself. That's a good idea, I thought `Process.Start()` was synchronous. Did the trick! – Harry Stuart Dec 20 '18 at 07:30
0

I don't know if this would help, but you could try getting rid out of one using and use other constructor of WaveFileWriter:

using (WaveFileWriter writer = new WaveFileWriter(fileName, waveFormat))
{
  writer.WriteData(testSequence, 0, testSequence.Length);
}
Michał Turczyn
  • 32,028
  • 14
  • 47
  • 69