Q:

Using threading to avoid too early data access

In my C# program, I have an automated sequence of function calls. They are called sequentially and each functions needed data depends on the predecessor. So every functions has to wait for another to finish.
I don't know how, but some functions results are not available at the start of the next function.
I tried to solve this problem by using threading:
Task taskA = Task.Factory.StartNew(() => generateData());
taskA.Wait();

if(taskA.IsCompleted)
{ 
     System.Windows.MessageBox.Show("Generation has been completed.");
     Task taskB = Task.Factory.StartNew(() => Thread.SpinWait(100000));
     taskB.Wait();
}
else
     System.Windows.MessageBox.Show("Generation has NOT been completed.");

nextFunctionCall();

But somehow, this doesn't work properly. 
The following functions stop working at some point and are in an endless while-loop.
I bypassed this threading simply by using at short timer:
generateData();
Thread.SpinWait(1000000000);
nextFunctionCall();

Of course that's not a nice solution...
Any idea why the threading isn't working?
Do I have to dispose the taskA? 
Thanks

A:

Sequential mechanisms; pipelines; or filter graphs can be implemented using TPL's DataFlow library in .NET.
MSDN:

The dataflow components build on the types and scheduling infrastructure of the TPL and integrate with the C#, Visual Basic, and F# language support for asynchronous programming. These dataflow components are useful when you have multiple operations that must communicate with one another asynchronously or when you want to process data as it becomes available. For example, consider an application that processes image data from a web camera. By using the dataflow model, the application can process image frames as they become available. 

DataFlow allows you to break-up your code into blocks specialized in a particular operation.  Once defined, you wire the blocks together.  It is up as to what defines a message to be passed on between blocks and when. 
DataFlow gives you complete control over the level of concurrency for each block as well as the number of messages a block can operate on at a given time.
In your example, you could define one block called generateDataBlock that is "wired" to push data onto a processing block.

