Is Par redundant?

Technical questions regarding the XTC tools and programming with XMOS.
User avatar
f_petrini
Active Member
Posts: 43
Joined: Fri Dec 11, 2009 8:20 am

Post by f_petrini »

Folknology wrote:Oh and you won't be able to use that same channel c on all 4 of those threads of course ;-)
I think you can. There's only two threads using the channel at a time so shouldn't that work?
Folknology wrote:And in main for example it serves no purpose since you can't have multiple Par{}s.
But the main function can consist of only sequential statements:

Code: Select all

int main(void)
{
	doSomethingFirst();
	doSomethingElseNext();

	return 0;
}
That should run in sequence and not in parallel, thus still needing the par-statement. ;)


User avatar
Folknology
XCore Legend
Posts: 1274
Joined: Thu Dec 10, 2009 10:20 pm

Post by Folknology »

I think you will have a problem with the channel when you get to the second par threads, try it. You are effectively allocating more than 2 ends to a channel its still in scope. Annoyingly you would think you could do the following to solve the scope issue :

Code: Select all

par {
  chan c;
  thread1();
  thread2();
}
..
par {
  chan c;
  thread3();
  thread4();
}
but you cannot, another reason why the par{} is not really a block adding to its confusing semantics IMHO
User avatar
Folknology
XCore Legend
Posts: 1274
Joined: Thu Dec 10, 2009 10:20 pm

Post by Folknology »

Here is a kinda ultimate code Oxymoron for XC:

Code: Select all

block {
  thread1();
  thread2();
}
;-)
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

Code: Select all

void someThread(void)
{
    chan c;
    while (1)
    {
        par
        {
            thread1(c);
            thread2(c);
        }

        ...do some sequential statements here...

        par
        {
            thread3(c);
            thread4(c);
        }
}
When you software rocketscientists :lol: has figured this out - can you explain it to me. Since I cannot run my example with the same channel in two seq pars - and I do not really know why.
It just locks at the channel com in thread3/thread4 - and I tried with both streaming and standard.
I do not get what I can do/ what I cannot do
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 »

It would seem more logical to declare/define a channel in the par{} where its used as that would make sense, you would never then try to use it elsewhere and the issue would not crop up. But the compiler will not let you do this which is just foolish.

To try and solve your problem Mika try using 2 channels with a simple example one for the first thread and another for the second if that works then we know that's the issue.

Code: Select all

void someThread(void)
{
    chan c,d;
    while (1)
    {
        par
        {
            thread1(c);
            thread2(c);
        }

        ...do some sequential statements here...

        par
        {
            thread3(d);
            thread4(d);
        }
}
User avatar
Folknology
XCore Legend
Posts: 1274
Joined: Thu Dec 10, 2009 10:20 pm

Post by Folknology »

I do not pretend to know what's going on underneath, I'm no expert, still consider myself a relative newbie here, we don't get to see all the magic happening underneath.

But I am presuming that the chan c issues is down to the following:

1) chan c declares a channel 'c' in scope across both pars to all threads 1 to 4
2) Each of the threads receives not a channel but a chanend see the prototype

Code: Select all

theadx(chanend)
3) The compiler seeing the par{} construct and the passing of a channel performs magic on the channel including initialising the channel and passing and end to to each thread in the par{}.
4) But maybe this isn't initialised when the compiler passes the ends to threads 3 and 4 and as such is in an unusable or illegal state.

The compiler should therefore catch this and produce and error or realise how its being used and makes sure the channel is in a state ready to be used for the second par{}.

But I'm guessing of course, maybe it does this and something else is causing your issue Mika.

However being able to define this in the Par{} scope would make it all much clearer.
User avatar
Folknology
XCore Legend
Posts: 1274
Joined: Thu Dec 10, 2009 10:20 pm

Post by Folknology »

Well figured that trying to solve this from the manual is not working, to many contradictions and ambiguities so wrote a quick test to see what happens:

Code: Select all

# include <platform.h>
# include <stdio.h>
# define CHARS 14

char msg1[] = "Hello channel1";
char msg2[] = "Hello channel2";

void txthread(chanend x,char data[],int size){
  for(int i = 0; i < size;i++){
    x <: data[i];
  }
}

void rxthread(chanend x, char rxbuf[],int size){
  for(int i = 0; i < size; i++) {
    x :> rxbuf[i];
  }
}

void runthreads() {
  char rxmsg[CHARS];
  chan c;
  par{
    txthread(c,msg1,CHARS);
    rxthread(c,rxmsg,CHARS);
  }
  printf("par 1 received %s\n",rxmsg);
  par {
    txthread(c,msg2,CHARS);
    rxthread(c,rxmsg,CHARS);
  } 
  printf("par 2 received %s\n",rxmsg);
}

int main ( void ) {
  runthreads();
  return 0;
}
This runs perfectly outputting the following on an XK-1:

Code: Select all

:-$ xcc chan-test.xc -target=XK-1 -o bin.xe
:-$ xrun --id 0 --io bin.xe
par 1 received Hello channel1
par 2 received Hello channel2
Thus the single channel c is being used twice without issues in this case. Can you check my logic that this is so?

regards
Al
Heater
Respected Member
Posts: 296
Joined: Thu Dec 10, 2009 10:33 pm

Post by Heater »

You beat me to the experiment.

All seems quite reasonable to me and just what I would expect.

After all those { and } imply to me that whatever is inside is totally out of scope outside. Basically does not exist any more. So why should the channel c not be reusable in another par statement. It's end point's are no longer required for the original threads. They don't exist any more in the second par.

I think this is a fine example of why the par construct is so neat.
User avatar
Folknology
XCore Legend
Posts: 1274
Joined: Thu Dec 10, 2009 10:20 pm

Post by Folknology »

I concur this suggests then that channels are indeed recycled between par constructs.
Heater
Respected Member
Posts: 296
Joined: Thu Dec 10, 2009 10:33 pm

Post by Heater »

Only one thing:

Your msg1 and msg2 are 14 character long strings. But they must have null terminations so the exchanged messages should be 15 characters.

Given that CHARS is defined as 14 only 14 bytes pass between threads though the channels and rxmsg message has no null termination.

I'm not sure why the printf does not throw up on the un-terminated strings it is asked to print.