Go to Post I love you ChiefDelphi times! - Amanda Morrison [more]
Home
Go Back   Chief Delphi > Technical > Programming > C/C++
CD-Media   CD-Spy  
portal register members calendar search Today's Posts Mark Forums Read FAQ rules

 
 
 
Thread Tools Rating: Thread Rating: 14 votes, 5.00 average. Display Modes
Prev Previous Post   Next Post Next
  #1   Spotlight this post!  
Unread 11-02-2010, 12:00
slavik262's Avatar
slavik262 slavik262 is offline
We do what we must because we can.
AKA: Matt Kline
FRC #0537 (Charger Robotics)
Team Role: Alumni
 
Join Date: Jan 2007
Rookie Year: 2007
Location: Sussex, WI
Posts: 310
slavik262 is a splendid one to beholdslavik262 is a splendid one to beholdslavik262 is a splendid one to beholdslavik262 is a splendid one to beholdslavik262 is a splendid one to beholdslavik262 is a splendid one to beholdslavik262 is a splendid one to behold
Send a message via AIM to slavik262
Task Creation and Semaphore Tutorial

Someone asked for help with Task creation and semaphores here, but I think this warrants its own thread.

Due to my work in other systems, I'm using task and thread interchangeably in this explanation. Sorry if this confuses anyone.

Task Creation and Arguments

To create a task, first write a task function (the function that will run in the separate thread). Note that this function will not automatically loop, so you'll need a loop structure unless you want it to do its work and exit immediately. I'll go over how to pass data into your function in a second.

To actually start the function in a different thread, create a Task class. The constructor takes a name for the class (pick whatever you want - this is just the name the task will have once created) as the first argument. The second argument is a function pointer to your task function. Use (FUNCPTR)myFunction, where myFunction is the name of your task function. This provides the memory address of where your function is located in the program so that the task can call it when it starts up. Leave the task priority and stack size (the last two arguments in the constructor) alone unless you know what you're doing. The defaults will work fine, and messing with the task priority can cause the program to behave unexpectedly.

To start your task, call the Start() method of the Task class you created. Start can take anywhere from 0 to 10 integer values, which are passed as arguments to the task function. Here's where things get fun:

Normally (in any other multithreading library I've used), thread/task functions take a void pointer as an argument. This lets you pass in a pointer to anything you want, and then use it in your function by just casting it back to its correct type. However, for whatever reason, VxWorks (the robot's Operating System) only allows you to pass in integers. If you're careful, you can trick your way around this and still do the same thing. You set an integer argument to the address of what you want to pass in, and cast it back to a pointer in the function. This works because the operating system the robot uses is a 32-bit OS, which means that its pointers are the same length as a 32-bit integer. An example follows.

Say you want a separate that spins a motor using a jaguar based on a joystick input (there's no reason why you couldn't just put it in the main task, but it's just an example). The entire process would be something like this:

Create a struct that contains all the data you'd need (in this case pointers to a Joystick and a Jaguar class).

Code:
struct SpinTaskArgs
{
     Joystick* joy;
     Jaguar* jag;
};
We'll also write our function for the task:

Code:
void MySpinTaskFn(UINT32 argPtr)
{
SpinTaskArgs* args = (SpinTaskArgs*)argPtr;

/*Do stuff with args, which is now a pointer to the
SpinTaskArgs struct you passed into the function*/
}
Notice how the function takes the integer argument and casts it into a pointer for your use. This will make more sense down the road.

In your main robot class, create an instance of this struct and set its members to point to their respective Joystick and Jaguar classes. Also create a task class

Code:
SpinTaskArgs spinArgs;
/*Assuming your joystick and jaguar are members of
the robot class and not allocated using the keyword new,*/
spinArgs.joy = &myJoystick;
spinArgs.jag = &myJaguar;

Task mySpinTask("SpinTask", (FUNCPTR)MySpinTaskFn);
Start up your task. We're going to pass the address of the SpinTaskArgs struct into the function as an integer, which is what the Start() function will accept. Notice now how this will work. To make VxWorks happy, you're passing the address of what you need in as an int, but it gets converted back to a pointer inside of your function.

Code:
mySpinTask.Start((UINT32)(&spinArgs));
Semaphores

Semaphores basically prevent two tasks from accessing the same variable/pointer at the same time. This is needed because if two or more tasks access the same data at the same time, the world ends (or at least the data can get corrupted and weird stuff can happen. )

To prevent this from happening, you can use critical regions around code that accesses shared data. Each piece of shared data (be it a variable, a struct, or a class) should have its own semaphore, and every part of your code that accesses it should have a critical region using that semaphore.

Say you have a vector of targets that you want to share between tasks.

Code:
Vector<Target> myTargets;
Create a semaphore using the type SEM_ID. I usually initialize the semaphores to binary ones using functions found in "semLib.h", but I'm pretty sure this isn't necessary.

Code:
SEM_ID targetSem;
WPILib provides a nice wrapper that automatically creates critical sections for you. So whenever you access your targets vector (or a pointer to it), surround the code with the following:

Code:
CRITICAL_REGION(targetSem)
/*code that accesses myTargets here*/
END_REGION
This way, only one critical region that uses targetSem will run at once. Others will stop execution and wait for the active critical region to exit.

If you have any more questions, I'd love to help. Shoot me an email or PM me.
__________________

Last edited by slavik262 : 11-02-2010 at 12:09.
Reply With Quote
 


Thread Tools
Display Modes Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
printf not working and UserProgram_StartupLibraryInit task deleted John Young C/C++ 4 08-02-2010 21:36
semaphore of the trailer frcchile Technical Discussion 3 26-01-2009 13:56
New LabVIEW TipJar Tutorial Video: Scalability, Modularity and Style. LVMastery NI LabVIEW 0 18-01-2009 14:56
Question about 3rd Tutorial ETA and FRC Modeler Motor Config Ted155 LabView and Data Acquisition 2 21-01-2007 19:45


All times are GMT -5. The time now is 15:21.

The Chief Delphi Forums are sponsored by Innovation First International, Inc.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi