4

This is a weird one, I have a Thread[] of worker threads which each process items in a ConcurrentQueue<string> until the queue is empty, at which point the rest of the program continues.

This works until about ~1500 items at which point all threads stay blocked in the WaitSleepJoin state and never process any of the items in the queue.

I've tried stepping through my code and it appears that the threads are still created, still started and are alive but get blocked immediately and never run their relevant function.

I'm completely flummoxed so any help would be appreciated!

The relevant sections of code are below:

Main Thread Segment:

            ConcurrentQueue<string> convertionQueue = new ConcurrentQueue<string>();
            List<Thread> converterThreads = new List<Thread>();
            Directory.GetFiles(_folderOne, "*.fdf", SearchOption.AllDirectories).ToList().ForEach(file => convertionQueue.Enqueue(file));
            Directory.GetFiles(_folderTwo, "*.fdf", SearchOption.AllDirectories).ToList().ForEach(file => convertionQueue.Enqueue(file));
            int filesDone = 0;
            int totalFiles = convertionQueue.Count;
            progressBar.Maximum = totalFiles;
            panel1.Visible = true;
            for (int i = 0; i < Environment.ProcessorCount; i++)
            {
                converterThreads.Add(new Thread(() => ConvThreadWorker(convertionQueue, ref filesDone)));
            }
            converterThreads.ForEach(thread => thread.Start());
            DateTime lastTick = DateTime.Now;
            int lastFilesDone = 0;
            int[] valuesSpeed = { 1, 1, 1, 1, 1 };
            int[] valuesTime = { 1, 1, 1, 1, 1 };
            int counter = 0;
            while (converterThreads.Any(thread => thread.IsAlive))
            {

                TimeSpan t = DateTime.Now - lastTick;
                int deltaFiles = filesDone - lastFilesDone;
                double speed = (float)t.TotalMilliseconds <= 0.0 ? 0.0 : deltaFiles / (float)t.TotalMilliseconds;
                double tMinus = speed <= 0 ? 0.0 : (totalFiles - filesDone) / speed;
                int currentSpeed = (int)(speed * 1000);
                int currentTime = (int)(tMinus / 1000);
                valuesSpeed[counter] = currentSpeed;
                valuesTime[counter] = currentTime;
                lblFilesLeft.Text = string.Format("{0}/{1}", filesDone, totalFiles);
                lblSpeed.Text = valuesSpeed.Sum() / 5 + " /s";
                lblTime.Text = valuesTime.Sum() / 5 + " s";
                lblFilesLeft.Update();
                lblSpeed.Update();
                lblTime.Update();
                progressBar.Value = filesDone;
                progressBar.Update();
                lastTick = DateTime.Now;
                lastFilesDone = filesDone;
                counter = ++counter % 5;
                Thread.Sleep(500);
            }

Worker Function:

private void ConvThreadWorker(ConcurrentQueue<string> queue, ref int fileCounter)
{
    while (!queue.IsEmpty)
    {
        string file;
        if (queue.TryDequeue(out file))
        {
            ConvToG(file);
            fileCounter++;
        }
    }
}

Convertion Function:

private void ConvToG(string file)
{
    MessageBox.Show("Entering Convertion Function");
    if (!_fileCreationDictionary.ContainsKey(file))
    {
        DateTime lastTimeModified = File.GetLastWriteTime(file);
       _fileCreationDictionary.AddOrUpdate(file, lastTimeModified, (key,oldvalue)=>lastTimeModified);
    }
    ProcessStartInfo procStart = new ProcessStartInfo
    {
        Arguments = file,
        UseShellExecute = true,
        FileName = Fdfg,
        WindowStyle = ProcessWindowStyle.Hidden
    };
    Process process = new Process {StartInfo = procStart};
    MessageBox.Show("Starting convertion process");
    process.Start();
    process.WaitForExit();
    MessageBox.Show("Finished");
}

The confusing part appears to be how this all revolves around the number of items in the queue, yet there appears to be no overflow.

UPDATE: Adding the mbox's shows that it freezes on the process.Start() section of code, with no errors and will not proceed past that point.

UPDATE 2: If UseShellExecute = false the code works. Which is very confusing to say the least.

ScottishTapWater
  • 3,656
  • 4
  • 38
  • 81
  • You are totally starving the Application messagepump. I'm not sure how long that can survive without air. – H H Jan 09 '17 at 13:58
  • 1500 files have been added, it doesn't process any of them before blocking – ScottishTapWater Jan 09 '17 at 14:08
  • @HenkHolterman this shouldn't take more than about 20 seconds to run and is only an internal tool, so we're not fussed if windows decides it's not responding – ScottishTapWater Jan 09 '17 at 14:09
  • And you're sure nothing is being processed? (And not just a Progressbar error). Where does it hang? Is the While loop running? – H H Jan 09 '17 at 14:15
  • Yep, the while loop is running and using the watch window I can see that the threads are all in waitsleepjoin mode, I have checked in windows explorer for the files that the convertion threads should generate to ensure that nothing is being processed. Please check my update – ScottishTapWater Jan 09 '17 at 14:17
  • "it freezes on the process.Start()" suggests it's a fault in that other program. But that's hard to relate to how full your queue is. Could be lots of things wrong with your diagnosis: an error in the first file to be processed, timings on the File system, ... Is anything else deleting or reading those fdf files in the same folders? – H H Jan 09 '17 at 14:23
  • If there is an error in the .fdf file the other program just outputs something along the lines of `This file is not in the correct format: 0 files converted` and then exits. No other program should be accessing these files. I'll unhide the output window and see what I get. – ScottishTapWater Jan 09 '17 at 14:25
  • Okay, so if I change `WindowStyle = ProcessWindowStyle.Hidden` to `WindowStyle = ProcessWindowStyle.Normal` it works for the first run of each thread and then stops. – ScottishTapWater Jan 09 '17 at 14:27
  • You do know that Process.Start is async, so that `MessageBox.Show("Finished")` is a lie? – H H Jan 09 '17 at 14:29
  • Yeah, my point was that that mbox never even shows up if the process window is hidden. Leading me to believe that somehow `Process.Start()` is actually causing them to block – ScottishTapWater Jan 09 '17 at 14:31
  • Also, I've just inspected the threads debug window and they are all stuck on `Process.Start()` – ScottishTapWater Jan 09 '17 at 14:40
  • Do you still stand by "it doesn't process any of them before blocking" ? – H H Jan 09 '17 at 14:51
  • If I change the `ProcessWindowStyle` to `Normal` it processes the first file for each thread (but never proceeds past the `Process.Start()` statement) and blocks – ScottishTapWater Jan 09 '17 at 15:04
  • I have no access to the source sadly or I'd embed it directly to save the resources needed to call a separate process. I'll see if I can reduce this down tonight. Thanks for your help! I'll get back to you – ScottishTapWater Jan 09 '17 at 15:47
  • How many threads are running in parallel? Can you try to limit to 1 thread only? – Ofir Winegarten Jan 09 '17 at 16:01
  • It's determined by the number of CPU cores, usually 4, if I run it on only 1 thread, the same thing happens – ScottishTapWater Jan 09 '17 at 23:27
  • 1
    Setting `UseShellExectute = false` appears to make this work, no idea why this seems determined based upon the number of files – ScottishTapWater Jan 10 '17 at 10:25

1 Answers1

1

I have done something similar with threads spawning processes to collate data. I had issues around the actual process starting and hanging. What I did to get my program working was something like this:

using (Process process = Process.Start(startInfo)) {
    if(process.WaitForExit(timeOutMilliseconds)) {
        MessageBox.Show("Process exited ok");
        //...snip
    } else {
        MessageBox.Show("Process did not exit in time!");
        //...snip
        process.Kill();
    }
}

There is a bit more going on in the background, regarding limiting the number of running process, etc, but I found that occasionally, for an unknown reason, that I would see several process in the task manager just hanging around forever.

Hope that helps?

Dai Bok
  • 3,451
  • 2
  • 53
  • 70