Set thread Timer priority

  • Thread starter Thread starter Giuseppe
  • Start date Start date
G

Giuseppe

Hello,
I use System.Threading.Timer to send every 40ms a UDP packet (audio data)
but, I' d like to increase timer priority. Is it possible?
Thank you

Giuseppe
 
As Daniel suggests, if you need guaranteed 40ms intervals, you need
something other than managed code (or a _very_ carefully crafted CF thread
to do it). And modifying priority of any app can lead to bad things if you
don't know the exact implications. This is especially true if you move to
the OpenNETCF ThreadEx, as it provides you enough capability to pre-empt
even the kernel. A pre-emption during a GC would be a bad, bad thing.

-Chris
 
As Daniel suggests, if you need guaranteed 40ms intervals, you need
something other than managed code (or a _very_ carefully crafted CF thread
to do it).
Something other... what do you mean, native code? Because, even if I create
a buffer of 160ms (with CF) of data (Timer every 200 ms) I see a random
delay (probably OS):
The code

public class dataState

{

public const int BUFFSIZE=3204;

public int CurrPosition;

public byte counter=0;

public byte[] Buff;

public byte[] buffSend=new byte[BUFFSIZE];

public bool Done=false;

public bool LedOn=true;

public MemoryMan mm=new MemoryMan();



public dataState( byte[] Buff)

{

this.Buff=Buff;

CurrPosition=4;

fillbuffSend();

}

public void fillbuffSend()

{

this.buffSend[0]=counter;

if (counter>=255)

counter=0;

else{

counter++;

}


if ( Buff.Length-CurrPosition>=BUFFSIZE)

{

Array.Copy( Buff,CurrPosition,buffSend,4,buffSend.Length-4);

CurrPosition+=BUFFSIZE;

}

else

{

Array.Copy(Buff,CurrPosition,buffSend,4,Buff.Length-CurrPosition-4);

CurrPosition+=BUFFSIZE;

Done=true;

}


}



}


/// <summary>

/// Descrizione di riepilogo per Class1.

/// </summary>

public class SoundSocket

{

#region "fields"

//private Socket _sock;

private IPEndPoint _TargetIP;

private int _UDPPort=(int)0xff00;

private Socket _sock=null;

//private NetworkStream _soundStream;

private WaveInfo wi=null;

private UdpClient listener = new UdpClient();

private IPEndPoint groupEP;

private System.Threading.Timer t;


public long tic=0;

public long tac=0;

public bool ThreadAlive=true;


#endregion

#region "properties"


/// <summary>

///

/// </summary>

public IPEndPoint TargetIP

{

get{

return _TargetIP;

}

set{_TargetIP=value;}

}

/// <summary>

///

/// </summary>

public int UDPPort

{

get

{

return _UDPPort;

}

set{_UDPPort=value;}

}



#endregion


public SoundSocket(IPAddress Target, int Port,string Path )

{


groupEP = new IPEndPoint(Target,Port);

//Fill Fields

_TargetIP=new IPEndPoint(Target,Port);

_UDPPort=Port;


//_soundStream=new NetworkStream(_sock,FileAccess.Write,false);


//get waveinfo

wi=new WaveInfo(Path);




}

public void PlayOnNetwork()

{



try

{

//listener.JoinMulticastGroup(_TargetIP,);

listener.Connect(groupEP);

dataState sd=new dataState(wi.AudioData);

t= new System.Threading.Timer(new TimerCallback(ref sendData),sd,0,200);


}

catch (Exception e)

{

MessageBox.Show(e.Message);


}

}



And modifying priority of any app can lead to bad things if you don't
know the exact implications. This is especially true if you move to the
OpenNETCF ThreadEx, as it provides you enough capability to pre-empt even
the kernel. A pre-emption during a GC would be a bad, bad thing.

Thank you all
Giuseppe
 
1. Timers (not including the Multimedia Timer) are inherently
nondeterministic. They won't fire in _less_ that the interval, but there's
no upper bound, and they're low priority. Just about anything can preempt
them.
2. Managed code is inherently nondeterministic. The GC can run an almost
any time, which can introduce long delays.

Deterministic behavior is not a simple thing in native code - it's very
touchy in managed code (not impossible, but very close to it). If you
really have timing constraints, you should be looking at native code, and
probably not using a Timer to achieve it.

--
Chris Tacke
Co-founder
OpenNETCF.org
Are you using the SDF? Let's do a case study.
Email us at d c s @ o p e n n e t c f . c o m
http://www.opennetcf.org/donate


Giuseppe said:
As Daniel suggests, if you need guaranteed 40ms intervals, you need
something other than managed code (or a _very_ carefully crafted CF
thread to do it).
Something other... what do you mean, native code? Because, even if I
create a buffer of 160ms (with CF) of data (Timer every 200 ms) I see a
random delay (probably OS):
The code

public class dataState

{

public const int BUFFSIZE=3204;

public int CurrPosition;

public byte counter=0;

public byte[] Buff;

public byte[] buffSend=new byte[BUFFSIZE];

public bool Done=false;

public bool LedOn=true;

public MemoryMan mm=new MemoryMan();



public dataState( byte[] Buff)

{

this.Buff=Buff;

CurrPosition=4;

fillbuffSend();

}

public void fillbuffSend()

{

this.buffSend[0]=counter;

if (counter>=255)

counter=0;

else{

counter++;

}


if ( Buff.Length-CurrPosition>=BUFFSIZE)

{

Array.Copy( Buff,CurrPosition,buffSend,4,buffSend.Length-4);

CurrPosition+=BUFFSIZE;

}

else

{

Array.Copy(Buff,CurrPosition,buffSend,4,Buff.Length-CurrPosition-4);

CurrPosition+=BUFFSIZE;

Done=true;

}


}



}


/// <summary>

/// Descrizione di riepilogo per Class1.

/// </summary>

public class SoundSocket

{

#region "fields"

//private Socket _sock;

private IPEndPoint _TargetIP;

private int _UDPPort=(int)0xff00;

private Socket _sock=null;

//private NetworkStream _soundStream;

private WaveInfo wi=null;

private UdpClient listener = new UdpClient();

private IPEndPoint groupEP;

private System.Threading.Timer t;


public long tic=0;

public long tac=0;

public bool ThreadAlive=true;


#endregion

#region "properties"


/// <summary>

///

/// </summary>

public IPEndPoint TargetIP

{

get{

return _TargetIP;

}

set{_TargetIP=value;}

}

/// <summary>

///

/// </summary>

public int UDPPort

{

get

{

return _UDPPort;

}

set{_UDPPort=value;}

}



#endregion


public SoundSocket(IPAddress Target, int Port,string Path )

{


groupEP = new IPEndPoint(Target,Port);

//Fill Fields

_TargetIP=new IPEndPoint(Target,Port);

_UDPPort=Port;


//_soundStream=new NetworkStream(_sock,FileAccess.Write,false);


//get waveinfo

wi=new WaveInfo(Path);




}

public void PlayOnNetwork()

{



try

{

//listener.JoinMulticastGroup(_TargetIP,);

listener.Connect(groupEP);

dataState sd=new dataState(wi.AudioData);

t= new System.Threading.Timer(new TimerCallback(ref sendData),sd,0,200);


}

catch (Exception e)

{

MessageBox.Show(e.Message);


}

}



And modifying priority of any app can lead to bad things if you don't
know the exact implications. This is especially true if you move to the
OpenNETCF ThreadEx, as it provides you enough capability to pre-empt even
the kernel. A pre-emption during a GC would be a bad, bad thing.

Thank you all
Giuseppe
 
1. Timers (not including the Multimedia Timer) are inherently
nondeterministic. They won't fire in _less_ that the interval, but
there's no upper bound, and they're low priority. Just about anything can
preempt them.
That is not good for me, in this case.
2. Managed code is inherently nondeterministic. The GC can run an almost
any time, which can introduce long delays.

Deterministic behavior is not a simple thing in native code - it's very
touchy in managed code (not impossible, but very close to it). If you
really have timing constraints, you should be looking at native code, and
probably not using a Timer to achieve it.
Ok, I'm writing a test code with evc++ that uses SetTimer to create a Timer,
that is correct? Can I suppose detrministic behaviour? To test my
application the timer turn on/off a led on my board. With an oscilloscope I
can see a delay of about 2ms....
....
TimerON=SetTimer(NULL,TIMER_ID,(UINT)TIMER_INTERVAL,(TIMERPROC)TimeOut);

....

VOID CALLBACK TimeOut()
{
LEDON=!LEDON;
WriteLedFault();

}


Thanks a lot
Giuseppe

--
Chris Tacke
Co-founder
OpenNETCF.org
Are you using the SDF? Let's do a case study.
Email us at d c s @ o p e n n e t c f . c o m
http://www.opennetcf.org/donate


Giuseppe said:
As Daniel suggests, if you need guaranteed 40ms intervals, you need
something other than managed code (or a _very_ carefully crafted CF
thread to do it).
Something other... what do you mean, native code? Because, even if I
create a buffer of 160ms (with CF) of data (Timer every 200 ms) I see a
random delay (probably OS):
The code

public class dataState

{

public const int BUFFSIZE=3204;

public int CurrPosition;

public byte counter=0;

public byte[] Buff;

public byte[] buffSend=new byte[BUFFSIZE];

public bool Done=false;

public bool LedOn=true;

public MemoryMan mm=new MemoryMan();



public dataState( byte[] Buff)

{

this.Buff=Buff;

CurrPosition=4;

fillbuffSend();

}

public void fillbuffSend()

{

this.buffSend[0]=counter;

if (counter>=255)

counter=0;

else{

counter++;

}


if ( Buff.Length-CurrPosition>=BUFFSIZE)

{

Array.Copy( Buff,CurrPosition,buffSend,4,buffSend.Length-4);

CurrPosition+=BUFFSIZE;

}

else

{

Array.Copy(Buff,CurrPosition,buffSend,4,Buff.Length-CurrPosition-4);

CurrPosition+=BUFFSIZE;

Done=true;

}


}



}


/// <summary>

/// Descrizione di riepilogo per Class1.

/// </summary>

public class SoundSocket

{

#region "fields"

//private Socket _sock;

private IPEndPoint _TargetIP;

private int _UDPPort=(int)0xff00;

private Socket _sock=null;

//private NetworkStream _soundStream;

private WaveInfo wi=null;

private UdpClient listener = new UdpClient();

private IPEndPoint groupEP;

private System.Threading.Timer t;


public long tic=0;

public long tac=0;

public bool ThreadAlive=true;


#endregion

#region "properties"


/// <summary>

///

/// </summary>

public IPEndPoint TargetIP

{

get{

return _TargetIP;

}

set{_TargetIP=value;}

}

/// <summary>

///

/// </summary>

public int UDPPort

{

get

{

return _UDPPort;

}

set{_UDPPort=value;}

}



#endregion


public SoundSocket(IPAddress Target, int Port,string Path )

{


groupEP = new IPEndPoint(Target,Port);

//Fill Fields

_TargetIP=new IPEndPoint(Target,Port);

_UDPPort=Port;


//_soundStream=new NetworkStream(_sock,FileAccess.Write,false);


//get waveinfo

wi=new WaveInfo(Path);




}

public void PlayOnNetwork()

{



try

{

//listener.JoinMulticastGroup(_TargetIP,);

listener.Connect(groupEP);

dataState sd=new dataState(wi.AudioData);

t= new System.Threading.Timer(new TimerCallback(ref sendData),sd,0,200);


}

catch (Exception e)

{

MessageBox.Show(e.Message);


}

}



And modifying priority of any app can lead to bad things if you don't
know the exact implications. This is especially true if you move to the
OpenNETCF ThreadEx, as it provides you enough capability to pre-empt
even the kernel. A pre-emption during a GC would be a bad, bad thing.

Thank you all
Giuseppe
 
No. SetTimer uses the same timer that the managed code is using, and it's
inherently nondeterministic. If you want determinism, you need a hardware
timer and an interrupt.

--
Chris Tacke
Co-founder
OpenNETCF.org
Are you using the SDF? Let's do a case study.
Email us at d c s @ o p e n n e t c f . c o m
http://www.opennetcf.org/donate


Giuseppe said:
1. Timers (not including the Multimedia Timer) are inherently
nondeterministic. They won't fire in _less_ that the interval, but
there's no upper bound, and they're low priority. Just about anything
can preempt them.
That is not good for me, in this case.
2. Managed code is inherently nondeterministic. The GC can run an almost
any time, which can introduce long delays.

Deterministic behavior is not a simple thing in native code - it's very
touchy in managed code (not impossible, but very close to it). If you
really have timing constraints, you should be looking at native code, and
probably not using a Timer to achieve it.
Ok, I'm writing a test code with evc++ that uses SetTimer to create a
Timer, that is correct? Can I suppose detrministic behaviour? To test my
application the timer turn on/off a led on my board. With an oscilloscope
I can see a delay of about 2ms....
...
TimerON=SetTimer(NULL,TIMER_ID,(UINT)TIMER_INTERVAL,(TIMERPROC)TimeOut);

...

VOID CALLBACK TimeOut()
{
LEDON=!LEDON;
WriteLedFault();

}


Thanks a lot
Giuseppe

--
Chris Tacke
Co-founder
OpenNETCF.org
Are you using the SDF? Let's do a case study.
Email us at d c s @ o p e n n e t c f . c o m
http://www.opennetcf.org/donate


Giuseppe said:
"<ctacke/>" <ctacke_AT_OpenNETCF_com> ha scritto nel messaggio
As Daniel suggests, if you need guaranteed 40ms intervals, you need
something other than managed code (or a _very_ carefully crafted CF
thread to do it).
Something other... what do you mean, native code? Because, even if I
create a buffer of 160ms (with CF) of data (Timer every 200 ms) I see a
random delay (probably OS):
The code

public class dataState

{

public const int BUFFSIZE=3204;

public int CurrPosition;

public byte counter=0;

public byte[] Buff;

public byte[] buffSend=new byte[BUFFSIZE];

public bool Done=false;

public bool LedOn=true;

public MemoryMan mm=new MemoryMan();



public dataState( byte[] Buff)

{

this.Buff=Buff;

CurrPosition=4;

fillbuffSend();

}

public void fillbuffSend()

{

this.buffSend[0]=counter;

if (counter>=255)

counter=0;

else{

counter++;

}


if ( Buff.Length-CurrPosition>=BUFFSIZE)

{

Array.Copy( Buff,CurrPosition,buffSend,4,buffSend.Length-4);

CurrPosition+=BUFFSIZE;

}

else

{

Array.Copy(Buff,CurrPosition,buffSend,4,Buff.Length-CurrPosition-4);

CurrPosition+=BUFFSIZE;

Done=true;

}


}



}


/// <summary>

/// Descrizione di riepilogo per Class1.

/// </summary>

public class SoundSocket

{

#region "fields"

//private Socket _sock;

private IPEndPoint _TargetIP;

private int _UDPPort=(int)0xff00;

private Socket _sock=null;

//private NetworkStream _soundStream;

private WaveInfo wi=null;

private UdpClient listener = new UdpClient();

private IPEndPoint groupEP;

private System.Threading.Timer t;


public long tic=0;

public long tac=0;

public bool ThreadAlive=true;


#endregion

#region "properties"


/// <summary>

///

/// </summary>

public IPEndPoint TargetIP

{

get{

return _TargetIP;

}

set{_TargetIP=value;}

}

/// <summary>

///

/// </summary>

public int UDPPort

{

get

{

return _UDPPort;

}

set{_UDPPort=value;}

}



#endregion


public SoundSocket(IPAddress Target, int Port,string Path )

{


groupEP = new IPEndPoint(Target,Port);

//Fill Fields

_TargetIP=new IPEndPoint(Target,Port);

_UDPPort=Port;


//_soundStream=new NetworkStream(_sock,FileAccess.Write,false);


//get waveinfo

wi=new WaveInfo(Path);




}

public void PlayOnNetwork()

{



try

{

//listener.JoinMulticastGroup(_TargetIP,);

listener.Connect(groupEP);

dataState sd=new dataState(wi.AudioData);

t= new System.Threading.Timer(new TimerCallback(ref sendData),sd,0,200);


}

catch (Exception e)

{

MessageBox.Show(e.Message);


}

}




And modifying priority of any app can lead to bad things if you don't
know the exact implications. This is especially true if you move to
the OpenNETCF ThreadEx, as it provides you enough capability to
pre-empt even the kernel. A pre-emption during a GC would be a bad,
bad thing.


Thank you all
Giuseppe
 
Timers are just timers, regardless of what language you are calling them
from (as Chris said). Managed code is going to give you some additional
things that you must take care with, as Chris said, but switching to C++
isn't going to change how timers themselves work. You need a different
architecture. Chris mentioned multimedia timers. You might also use
WaitForSingleObject() with a time-out in a high-priority thread as a means
of 'scheduling' some activity.

Paul T.


Giuseppe said:
1. Timers (not including the Multimedia Timer) are inherently
nondeterministic. They won't fire in _less_ that the interval, but
there's no upper bound, and they're low priority. Just about anything
can preempt them.
That is not good for me, in this case.
2. Managed code is inherently nondeterministic. The GC can run an almost
any time, which can introduce long delays.

Deterministic behavior is not a simple thing in native code - it's very
touchy in managed code (not impossible, but very close to it). If you
really have timing constraints, you should be looking at native code, and
probably not using a Timer to achieve it.
Ok, I'm writing a test code with evc++ that uses SetTimer to create a
Timer, that is correct? Can I suppose detrministic behaviour? To test my
application the timer turn on/off a led on my board. With an oscilloscope
I can see a delay of about 2ms....
...
TimerON=SetTimer(NULL,TIMER_ID,(UINT)TIMER_INTERVAL,(TIMERPROC)TimeOut);

...

VOID CALLBACK TimeOut()
{
LEDON=!LEDON;
WriteLedFault();

}


Thanks a lot
Giuseppe

--
Chris Tacke
Co-founder
OpenNETCF.org
Are you using the SDF? Let's do a case study.
Email us at d c s @ o p e n n e t c f . c o m
http://www.opennetcf.org/donate


Giuseppe said:
"<ctacke/>" <ctacke_AT_OpenNETCF_com> ha scritto nel messaggio
As Daniel suggests, if you need guaranteed 40ms intervals, you need
something other than managed code (or a _very_ carefully crafted CF
thread to do it).
Something other... what do you mean, native code? Because, even if I
create a buffer of 160ms (with CF) of data (Timer every 200 ms) I see a
random delay (probably OS):
The code

public class dataState

{

public const int BUFFSIZE=3204;

public int CurrPosition;

public byte counter=0;

public byte[] Buff;

public byte[] buffSend=new byte[BUFFSIZE];

public bool Done=false;

public bool LedOn=true;

public MemoryMan mm=new MemoryMan();



public dataState( byte[] Buff)

{

this.Buff=Buff;

CurrPosition=4;

fillbuffSend();

}

public void fillbuffSend()

{

this.buffSend[0]=counter;

if (counter>=255)

counter=0;

else{

counter++;

}


if ( Buff.Length-CurrPosition>=BUFFSIZE)

{

Array.Copy( Buff,CurrPosition,buffSend,4,buffSend.Length-4);

CurrPosition+=BUFFSIZE;

}

else

{

Array.Copy(Buff,CurrPosition,buffSend,4,Buff.Length-CurrPosition-4);

CurrPosition+=BUFFSIZE;

Done=true;

}


}



}


/// <summary>

/// Descrizione di riepilogo per Class1.

/// </summary>

public class SoundSocket

{

#region "fields"

//private Socket _sock;

private IPEndPoint _TargetIP;

private int _UDPPort=(int)0xff00;

private Socket _sock=null;

//private NetworkStream _soundStream;

private WaveInfo wi=null;

private UdpClient listener = new UdpClient();

private IPEndPoint groupEP;

private System.Threading.Timer t;


public long tic=0;

public long tac=0;

public bool ThreadAlive=true;


#endregion

#region "properties"


/// <summary>

///

/// </summary>

public IPEndPoint TargetIP

{

get{

return _TargetIP;

}

set{_TargetIP=value;}

}

/// <summary>

///

/// </summary>

public int UDPPort

{

get

{

return _UDPPort;

}

set{_UDPPort=value;}

}



#endregion


public SoundSocket(IPAddress Target, int Port,string Path )

{


groupEP = new IPEndPoint(Target,Port);

//Fill Fields

_TargetIP=new IPEndPoint(Target,Port);

_UDPPort=Port;


//_soundStream=new NetworkStream(_sock,FileAccess.Write,false);


//get waveinfo

wi=new WaveInfo(Path);




}

public void PlayOnNetwork()

{



try

{

//listener.JoinMulticastGroup(_TargetIP,);

listener.Connect(groupEP);

dataState sd=new dataState(wi.AudioData);

t= new System.Threading.Timer(new TimerCallback(ref sendData),sd,0,200);


}

catch (Exception e)

{

MessageBox.Show(e.Message);


}

}




And modifying priority of any app can lead to bad things if you don't
know the exact implications. This is especially true if you move to
the OpenNETCF ThreadEx, as it provides you enough capability to
pre-empt even the kernel. A pre-emption during a GC would be a bad,
bad thing.


Thank you all
Giuseppe
 
Timers are just timers, regardless of what language you are calling them
from (as Chris said). Managed code is going to give you some additional
things that you must take care with, as Chris said, but switching to C++
isn't going to change how timers themselves work. You need a different
architecture. Chris mentioned multimedia timers. You might also use
WaitForSingleObject() with a time-out in a high-priority thread as a means
of 'scheduling' some activity.

Paul T.
Ok, now all is clear. But I have a last question. I have a WINCE device and
I'd like to send audio over ethernet. The problem is here. Audio can be live
or from audio file. I'd like to use UDP protocol then, in your opinion (with
an ARM 200Mhz), can I create, even using hw timer, parallel threads that
send UDP packets (about 300 bytes) every 40 ms? It can be done with managed
code?
Now I do some test (native code) with WaitForSingleObject...and I say you.

Thank you all
Giuseppe
 
Whoa there! UDP is non-deterministic, too. You do *not* want to send the
packets on the assumption that they will be received and played just as they
arrive. That would be a hugely poor assumption. You need to either a) use
a standard streaming format, or b) send information on how the sound is to
be played when you start (data rate, etc.), and then just send the data as
fast as you damn well can, letting the receiver reconstruct the audio stream
and send it to its sound hardware at the appropriate rate.

Paul T.
 
Whoa there! UDP is non-deterministic, too. You do *not* want to send the
packets on the assumption that they will be received and played just as
they arrive. That would be a hugely poor assumption. You need to either
a) use a standard streaming format, or

Audio file: wav PCM, 16 bit@8KHz
then 8 sample (2 bytes) every ms--> I send a packet of (8*2*40=640 bytes
every 40ms) then I can use a player with a buffer (double) of 80ms.

b) send information on how the sound is to
be played when you start (data rate, etc.), and then just send the data as
fast as you damn well can, letting the receiver reconstruct the audio
stream and send it to its sound hardware at the appropriate rate.
That is true but I can saturate the band. Probably the right way is to
comunicates 'buffer low' to the client that sends audio packets, but how can
I achive that?.
Anyway, thank you for great help.
Giuseppe
 
There are network connections where you'll never be able to force the
transmission and reception of buffers at that rate. Run a ping with the
buffer size you plan to use between the two machines you plan to use. How
often does it happen in 40ms? On the other hand, why not change the amount
of data you're sending based on how long it's been since the last send?
That at least helps account for non-determinism in scheduling the sending of
packets.

Why are you doing this with Windows CE on a relatively slow processor as the
server anyway?

As far as communicating "low", it's entirely your proprietary protocol,
right? Come up with something.

Paul T.
 
Back
Top