Ending/stopping a parrallel task and how to restart tasks

Technical questions regarding the XTC tools and programming with XMOS.
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Ending/stopping a parrallel task and how to restart tasks

Post by lilltroll »

What is the best way to end several task running within a par() ?

I have several tasks running inside a par()
One of the tasks (master) has a for loop that will be finished after some time. When that task is finished I would like all other parallel task to stop as well, and the main program to continue to the next par.


par{
master(channels);
slave_1(channels);
slave_2(channels);
slave_3(channels);
slave_4(channels);
}

par{
another_master(.....


Probably not the most confused programmer anymore on the XCORE forum.
User avatar
skoe
Experienced Member
Posts: 94
Joined: Tue Apr 27, 2010 10:55 pm

Post by skoe »

Send a message through a channel to to tell them that they should cancel. This would be a clean design IMHO.
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

skoe wrote:Send a message through a channel to to tell them that they should cancel. This would be a clean design IMHO.
How do I send a message through a channel, without the use of 7 channels if I have 7 slave processes?
A channel must have only 2 channel ends. I would need 7 different channels in the master.
Can it be done in some daisy chain? The stop signal travels from the master to the first slave - from first slave to second slave and so on.

I cannot afford using up 7 channels just for a stop token.

There is some functions for control tokens. Can I use them ?

outct Streams out a control token on a channel end
Probably not the most confused programmer anymore on the XCORE forum.
User avatar
skoe
Experienced Member
Posts: 94
Joined: Tue Apr 27, 2010 10:55 pm

Post by skoe »

Yes, I meant one channel per thread. AFAIK there's nothing like a broadcast/multicast in XMOS, so you'd need to use a loop over the channels. Technically you can use one channel end to address all channel ends of the the slave threads, one by one.

I don't know if XC supports this. If not you can use inline assembly to take one channel end, set its destination to the others (setd) and send data or a control token (out/outct) to each of them in a loop. This is one of the things that makes XC look a bit unhandy to me, but maybe I didn't find the trick yet and it's possible without inline assembly.
User avatar
snowman
Member
Posts: 13
Joined: Fri Dec 11, 2009 10:51 am

Post by snowman »

7 channels would be the clean way. I like to call the technique poisoning - a control token is the posion and each thread passes the token to the next thread, so eventually all threads will die.

Bear in mind there are 32 channel ends on each core and you can reuse them in the next par.

If that's still too much, just use a shared variable:

Code: Select all

void masterr(int stop_ptr)
{
      asm("stw %0, %1[0]" :: "r"(1), "r"(stop_ptr));
}
void slavee(int stop_ptr)
{
      int stop;
      do {
               asm("ldw %0, %1[0]" : "=r"(stop) : "r"(stop_ptr));
      } while (!stop);
}
int ptr(const int &var);
int main()
{
     int stop = 0;
     par {
          masterr(ptr(stop));
          slavee(ptr(stop));
          slavee(ptr(stop));
     }
     return 0;
}
where ptr gives you the address of stop (compiled in a separate C file):

Code: Select all

int ptr(const int *var)
{
  return (int)var;
}
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

To make it easier to read I solved it with a struct like this.

Code: Select all

typedef const struct{
	unsigned int run;
	unsigned int mode;
}control_struct;
A function like this:

Code: Select all

void enable(control_struct &control,unsigned int mode){
	control.run=1;
	control.mode=mode;
	return;
}
And in the main it looks like this:

Code: Select all

	enable(control,0);
	par
	{
		I2S_slave(c_DAC , c_ADC , control);
		lmsfind(c_ADC,c_DAC ,W0, FXfir_L , control);
	}
	enable(control,1);
	printstr("\nStep2\n");
	
	par
	{
		I2S_slave(c_DAC , c_ADC , control);
		lmsfind(c_ADC , c_DAC , W1, FXfir_R, control);
	}
	
	printstr("Step3\n");
The program passes Step1 and Step2, but stops in the second par.
In debug mode I can find the stopping point.

The I2S_slave has stopped at:

Code: Select all

c_ADC[0]<:(TEMP_ADC);
(c_ADC = @0x1deb8)

And the lmsfind has stopped at

Code: Select all

c_IN[0] :> Y;
(c_IN = @0x1deb8)

Somehow the states of the channels are not the same the second time compared to the first time.
How do i terminate/reset or solve the issue :?: :?: :?:
It's 2 channel ends of the same channels - why is it locked ??
Probably not the most confused programmer anymore on the XCORE forum.
User avatar
Folknology
XCore Legend
Posts: 1274
Joined: Thu Dec 10, 2009 10:20 pm

Post by Folknology »

I'm guessing c_DAC , c_ADC are channels?

If so they can have only 2 endpoints. by trying to reuse them in the second Par you are effectively trying to add new endpoints I think. Try using new channels in the second par.

*Update - Sorry I'm obviously not paying attention, you seem to be using arrays of channels, Thus I cannot see if these are being globally declared/reused or what. But it could be that you are trying to assign/reassign more than 2 endpoints to one or more of the channels.

regards
Al
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

Folknology wrote:I'm guessing c_DAC , c_ADC are channels?

If so they can have only 2 endpoints. by trying to reuse them in the second Par you are effectively trying to add new endpoints I think. Try using new channels in the second par.

*Update - Sorry I'm obviously not paying attention, you seem to be using arrays of channels, Thus I cannot see if these are being globally declared/reused or what. But it could be that you are trying to assign/reassign more than 2 endpoints to one or more of the channels.

regards
Al
Ahaa, it's an array but I use the same channels in the array in both par.
(The second par doesn't start before the functions from the first par is terminated.)
Can I "kill" channels in XC and reuse them later, or do I need to use ASM or something from the xs1.h like start_streaming / stop streaming?
Probably not the most confused programmer anymore on the XCORE forum.
User avatar
Folknology
XCore Legend
Posts: 1274
Joined: Thu Dec 10, 2009 10:20 pm

Post by Folknology »

I wondered if you could put the chan declarations inside the Par block to limit scope but that's now allowed, I'm not even sure its really a block per se rather a syntactical convenience.

So the questions becomes can one reuse/recycle channels?
User avatar
Folknology
XCore Legend
Posts: 1274
Joined: Thu Dec 10, 2009 10:20 pm

Post by Folknology »

I should also point out that you are on a bit of a sticky wicket:
1) You are not allocating threads to a core "on stdcore[x] : ...." this is dicouraged as eventually may not be allowed.
2) When you do allocate threads to cores you will not be able to use multiple par statements in Main try it.

Over all maybe another pattern may be more suitable to your problem, I might be tempted to perhaps use a Replicator with a much higher abstraction, that would mean making your thread functions more generic, but capable of morphing based on channel signalling perhaps and or via a mode integer passed in through the replicator index or derivative thereof. A combination of these techniques may likely even be required.

But to be fair at this point I do not fully understand the exact problem that you are trying to solve so I may be spouting nonsense ;-)

regards
Al