4
votes

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.

1
You are totally starving the Application messagepump. I'm not sure how long that can survive without air. - Henk Holterman
1500 files have been added, it doesn't process any of them before blocking - Persistence
@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 - Persistence
And you're sure nothing is being processed? (And not just a Progressbar error). Where does it hang? Is the While loop running? - Henk Holterman
Setting UseShellExectute = false appears to make this work, no idea why this seems determined based upon the number of files - Persistence

1 Answers

1
votes

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?