3
class MultiThreading
{
    public class ThreadClass
    {
        public string InputString { get; private set; }
        public int StartPos { get; private set; }
        public List<SearchAlgorithm.CandidateStr> completeModels;
        public List<SearchAlgorithm.CandidateStr> partialModels;

        public ThreadClass(string s, int sPos)
        {
            InputString = s;
            StartPos = sPos;
            completeModels = new List<SearchAlgorithm.CandidateStr>();
            partialModels = new List<SearchAlgorithm.CandidateStr>();
        }

        public void Run(int strandID)
        {
            Thread t = new Thread(() => this._run(strandID));
            t.Start();
        }

        private void _run(int strandID)
        {
            SearchAlgorithm.SearchInOneDirection(strandID, ref this.completeModels, ref this.partialModels);
        }

        public static void CombineResult(
            List<ThreadClass> tc,
            out List<SearchAlgorithm.CandidateStr> combinedCompleteModels,
            out List<SearchAlgorithm.CandidateStr> combinedPartialModels)
        {
            // combine the result
        }
    }
}

class Program
    {

        static void Main(string s, int strandID)
        {
            int lenCutoff = 10000;
            if (s.Length > lenCutoff)
            {
                var threads = new List<MultiThreading.ThreadClass>();
                for (int i = 0; i <= s.Length; i += lenCutoff)
                {
                    threads.Add(new MultiThreading.ThreadClass(s.Substring(i, lenCutoff), i));
                    threads[threads.Count - 1].Run(strandID);
                }


                **// How can I wait till all thread in threads list to finish?**
            }
        }
    }

My question is how can I wait till all threads in "threads" list to finish and then do the call CombineResult method?

Thanks

Mavershang
  • 1,266
  • 2
  • 15
  • 27
  • 1
    If you're using c# 4.0, have you considered using the [Task Parallel Library](http://msdn.microsoft.com/en-us/library/dd460717.aspx)? Vastly preferable to writing your own threading directly. – Paul Phillips Jul 26 '12 at 16:31
  • You are probably best off reading up on the [Task Class](http://msdn.microsoft.com/en-us/library/dd235678) which has a built in `WaitAll` method. – nicholas Jul 26 '12 at 16:31
  • possible duplicate of [How to wait for thread to finish with .NET?](http://stackoverflow.com/questions/1584062/how-to-wait-for-thread-to-finish-with-net) – Peter Ritchie Jul 26 '12 at 16:33
  • You'll eventually have a problem due to using `List` from multiple threads at the same time. – user7116 Jul 26 '12 at 16:42
  • 1
    I'd suggest not having a `Run` and `_run` method in the same class. It's just asking for confusion or StackOverflow errors (if someone uses the wrong one). – Servy Jul 26 '12 at 16:46

3 Answers3

5

You can add a List<Thread> structure to keep record of all your threads

private List<Thread> threads = new List<Thread>();

Then populate the list with the threads

public void Run(int strandID)
{
    Thread t = new Thread(() => this._run(strandID));
    t.Start();
    threads.Add(t);
}

Lastly, you can have a method that calls Join for each thread in a list. It is usually a good practise to have a timeout delay so your program will not block forever (in case there is a bug in a thread)

public void WaitAll(List<Thread> threads, int maxWaitingTime)
{
    foreach (var thread in threads)
    {
        thread.Join(maxWaitingTime); //throws after timeout expires
    }
}


An alternative would be to use a Task class and to call Task.WaitAll
oleksii
  • 35,458
  • 16
  • 93
  • 163
  • Instead of implementing the WaitAll function in the class using it, I would implement it as an extension method instead on IEnumerable – JG in SD Jul 26 '12 at 16:33
  • Will the WaitAll methods break the parallel calculation? – Mavershang Jul 26 '12 at 17:44
  • @Mavershang no it will not. If the calculation has not finished by the time `maxWaitingTime` elapses the call from `WaitAll` will simply return. Meanwhile your thread will carry on calculations. If you need to break calculations you would need to allow [cancelations](http://msdn.microsoft.com/en-us/library/dd997396.aspx). It is really difficult to make it right with raw `Thread`. And do not call `Thread.Abort` google why. – oleksii Jul 26 '12 at 18:57
1

Have ThreadClass expose a means to join the thread:

    private Thread nativeThread;
    public void Run(int strandID)
    {
        nativeThread = new Thread(() => this._run(strandID));
        nativeThread.Start();
    }

    public void Join()
    {
        nativeThread.Join();
    }

And then use ThreadClass.Join on each thread after you start them:

    var threads = new List<ThreadClass>();
    for (int i = 0; i <= s.Length; i += lenCutoff)
    {
        threads.Add(new ThreadClass(s.Substring(i, lenCutoff), i));
        threads[threads.Count - 1].Run(strandID);
    }

    // Waits for each thread to finish in succession
    threads.ForEach(t => t.Join());

Or, throw away your ThreadClass and enjoy System.Threading.Tasks:

// e.g. class Models { Complete; Partial; }
// private Models Search(string source, int offset, int length, int ID)
var tasks = new List<Task<Models>>(
    from x in Enumerable.Range(0, s.Length / lenCutoff)
    select Task.Factory.StartNew<Models>(
        () => Search(s, x, lenCutoff, strandID));
);

// private Models CombineResults(IEnumerable<Models> results)
var combine = Task.Factory.ContinueWhenAll<Models>(
    tasks.ToArray(),
    ts => CombineResults(ts.Select(t => t.Result)));

combine.Wait();

Models combinedModels = combine.Result;
user7116
  • 63,008
  • 17
  • 141
  • 172
1

Well I see the answer has already been chosen, but I had already started on writing a solution using System.Threading.Tasks as proposed by several others. Rather than using LINQ, I have tried to match the structure of the original code as much as possible:

class SearchClass
{
    public String InputString { get; private set; }
    public int StartPos { get; private set; }
    public List<string> completeModels;
    public List<string> partialModels;

    public SearchClass(string s, int sPos)
    {
        InputString = s;
        StartPos = sPos;
        completeModels = new List<string>();
        partialModels = new List<string>();
    }

    public void Run(int strandID)
    {
        // SearchAlgorithm.SearchInOneDirection(...);
    }

    // public static void CombineResult(...){ };
}

class Program
{
    static void Main(string s, int strandID)
    {      
        int lenCutoff = 10000;

        if (s.Length > lenCutoff)
        {
            var searches = new List<SearchClass>();
            var tasks = new List<System.Threading.Tasks.Task>();

            for (int i = 0; i < s.Length; i += lenCutoff)
            {
                SearchClass newSearch = new SearchClass(s.Substring(i, lenCutoff), i);
                searches.Add(newSearch);
                tasks.Add(System.Threading.Tasks.Task.Factory.StartNew(()=>newSearch.Run(strandID)));
            }

            System.Threading.Tasks.Task.WaitAll(tasks.ToArray());

            // Combine the result
        }
    }
}
nicholas
  • 2,969
  • 20
  • 39