Re: How to set scheduling in NSThread based application
Re: How to set scheduling in NSThread based application
- Subject: Re: How to set scheduling in NSThread based application
- From: Gilles Celli <email@hidden>
- Date: Mon, 12 Feb 2007 22:02:49 +0100
Shawn,
Thanks for your quick reply.
To get the data from the multimeter a 'READ' command is sent to it
every 0.5seconds.
I'm polling with gettimeofday() the time, and sleeping with a
nanosleep of 250000000L after the acquisition, something like this:
I wonder in fact if this is the right way to do it.... so please
don't laugh at my hobbyist-programming horror code ;-)
So here comes the first execution after detaching the first NSThread:
// Start and loop the acquisition until the user clicked the button
'Disconnect'
while ( threadIsRunning ) {
gettimeofday(&tval, NULL);
if ( ( tval.tv_usec == SECOND_ZERO ) || (tval.tv_usec ==
HALF_SECONDS_IN_MICROSEC ) )
{
// Read one shot from the Keithley 2700 multimeter as string
k2700_read_data( fdSerial, keithleyRawDataBufferCString );
// Store data
supraData[currentRow].supraChannel = atof
( keithleyRawDataBufferCString );
....
....
// Write data
tsoft_file_handler(....);
nanosleep()
}
}
I first open the device like this:
int openSerialPort(const char *deviceFilePath)
{
int fileDescriptor = -1;
static struct termios gOriginalTTYAttrs;
struct termios rs232_attr;
fileDescriptor = open(deviceFilePath, O_RDWR | O_NOCTTY | O_NONBLOCK
| O_NDELAY);
...
...
rs232_attr = gOriginalTTYAttrs;
//printf("Current input baud rate is %d\n", (int) cfgetispeed
(&rs232_attr));
//printf("Current output baud rate is %d\n", (int) cfgetospeed
(&rs232_attr));
// Clear struct for new port settings
bzero( &rs232_attr, sizeof(rs232_attr) );
// Set Baudrate to 9600 bps by default
cfsetospeed( &rs232_attr, B9600);
cfsetispeed( &rs232_attr, B9600); // this line is important
// CS8 : 8n1 (8bit, no parity, 1 stopbit)
// CLOCAL : local connection, no modem control
// CREAD : enable receiving characters
// Enable the receiver and set local mode...
rs232_attr.c_cflag |= (CLOCAL | CREAD);
// Character and parity settings No parity (8N1):
rs232_attr.c_cflag |= CS8;
rs232_attr.c_cflag &= ~PARENB; // Set NO parity
rs232_attr.c_cflag &= ~CSTOPB; // Set 1 Stop Bit
rs232_attr.c_cflag &= ~CSIZE;
// Set raw input (non-canonical) mode, with reads blocking until
either a single character
// has been received or a one second timeout expires.
// See tcsetattr(4) ("man 4 tcsetattr") and termios(4) ("man 4
termios") for details.
cfmakeraw(&rs232_attr);
rs232_attr.c_cc[VMIN] = 1;
rs232_attr.c_cc[VTIME] = 10;
}
for Reading data:
void k2700_read_data( int fileDescriptor, char *k2700Buffer )
{
if ( write( fileDescriptor, ":READ?\r", 7) == -1)
// Read characters into our buffer until we get a CR or LF
bufPtr = buffer;
do
{
numBytes = read(fileDescriptor, bufPtr, &buffer[sizeof(buffer)] -
bufPtr - 1);
if (numBytes == -1)
printf("Error reading from modem - %s(%d).\n", strerror(errno),
errno);
else if (numBytes > 0)
{
bufPtr += numBytes;
if (*(bufPtr - 1) == '\n' || *(bufPtr - 1) == '\r')
{
break;
}
}
else {
printf("Nothing read.\n");
}
} while (numBytes > 0);
// NUL terminate the string and see if we got an OK response
*bufPtr = '\0';
// Example of 'buffer' output for 16 channels read from the Keithley
2700
//
-3.80132586E-01VDC,-3.86980623E-01VDC,-3.94014210E-01VDC,-4.01051730E-01
VDC,-4.08394873E-01VDC,-4.15606618E-01VDC,
4.22780007E-01VDC,-4.29845721E-01VDC,-4.42195922E-01VDC,-4.49257135E-01V
DC,-4.56305921E-01VDC,-4.63421822E-01VDC,-4.70700681E-01VDC,-4.77828979E
-01VDC,-4.85090911E-01VDC,-4.92547929E-01VDC
// Extract the value of each channel without UNITS (VDC) and put
them in an 'k2700Buffer'
// For performance reason we don't use a for() loop
k2700Buffer[0] = buffer[0];
k2700Buffer[1] = buffer[1];
k2700Buffer[2] = buffer[2];
k2700Buffer[3] = buffer[3];
k2700Buffer[4] = buffer[4];
k2700Buffer[5] = buffer[5];
k2700Buffer[6] = buffer[6];
k2700Buffer[7] = buffer[7];
k2700Buffer[8] = buffer[8];
k2700Buffer[9] = buffer[9];
k2700Buffer[10] = buffer[10];
k2700Buffer[11] = buffer[11];
k2700Buffer[12] = buffer[12];
k2700Buffer[13] = buffer[13];
k2700Buffer[14] = buffer[14];
k2700Buffer[15] = (char)0; // We stop here by appending a '\0' to
proper end string k2700Buffer[]
// since we don't want to append the chars "VDC" for
function atof()
}
On Feb 12, 2007, at 5:57 PM, Shawn Erickson wrote:
On 2/12/07, Shawn Erickson <email@hidden> wrote:
On 2/12/07, Gilles Celli <email@hidden> wrote:
> Hi,
>
> I've written a data acquisition-program under Cocoa which detach 2
> new NSThreads:
>
> One which collects data every 0.5 seconds (full second and
> millisecond 500 via gettimeofday()) from a multimeter via USB-to-
> Serial Adapter,
> and another one which displays the graph of the data in
NSTableView
> and with the Open-Source-Based
> SM2DGraphView.
...snip...
> Any suggestions are greatly appreciated.
500 milliseconds is 50 times larger then the current scheduling
quantum. I really don't think thread scheduling is an issue....
unless
you have to capture something in a relatively narrow time period
(i.e.
500 ms +/- a few to 10s of milliseconds).
Are you sure you are not affected by clock skew introduced in the way
you are calculating times? Or by some contested lock you are using to
protect the data you are capturing and displaying?
Another possibility, not knowing how your capture thread is coded, is
that your capture thread is chewing to much CPU time (polling to
quickly) and as a result its priority gets suppressed due to fairness
and every now and then due to it lower priority loses out to another
thread with higher priority at just the wrong time.
-Shawn
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden