You generally use a list variable to supply the input data to each instance, each instance gets a member of the list variable to work upon, additionally you can supply common data also to the instances.
The index of the list which will match the current step/instance (the counter for the instances) is retrieved using
tw.system.step.counter, so the index of the current item for the list will be tw.system.step.counter - 1 since list indexes start with 0
A simple use case is lets say a person chooses how many approvers will be for a given task, we will have to generate as many tasks as the number of approvers added.
You can have a scenario where all approvers will need to approve before we can move forward, or a scenario where any approver approving moves the flow forward, this is done by conditional wait till a certain condition is true and cancelling remaining instances, you may have a scenario that when a certain condition is met come out of the loop but let the remaining instances run, when the additional instances exit they will introduce additional token and you will have multiple tokens in you process.
The most complex scenario i have seen for a multi-instance loop is where in a user chooses approvers we generate tasks for each approver, but any one of the approver can add additonal approvers and we have to add as many additional approvers to the task list but the approval task is essentially same.
The solution used was a self joining multi instance linked process, it is'nt easy to implement especially in the conditional exit area and keeping in mind pass by reference. the exit condition was if any approver rejects cancel all remaining tasks and exit to main process or wait for all approvals adhoc and main ones to come in.
I am attaching a skeleton of the implementation, its not a fully executing one. later I will try to post a fully working version also.