While I am familiar with threading and have used it many times I have never done so in C++. Can anyone refer me to a good threading tutorial?
For what environment? Threads are a system-dependent feature and can be implemented at various levels of the system.
POSIX is a pretty commonly used threading library on Linux-based systems; you basically call a “create thread” function and pass it a function pointer for whatever code it is that you want to run asynchronously. Primitives like mutexes and semaphores are included.
This is a good overview of POSIX threading.
for the cRio.
Here is another old thread dedicated to it. http://www.chiefdelphi.com/forums/showthread.php?t=71138
On the CRIO, they are called tasks. I am not sure how to use them yet myself. That part of the WPI manual is blanked out. Look at the tasks.h file in the WPILib folder. It helps a little. Also look at the camera examples in WindRiver. I believe they are using seperate tasks for image aquisition.
hope this helps a little
Does anybody have any sample code of a thread (task) that they have got working. At the moment it appears that the task is being deleted.
Hi nickmagus,
I’d recommend you use the WPILib Task class, which is a simple wrapper over the VxWorks task/thread API. Here’s some sample code to get you started:
To define a task, you have to give it a name. The task will show up in debugging as FRC_task_name, where task_name is the value passed to the Task constructor. The second argument to the constructor is a FUNCPTR, which is your threading function.
MyRobot::RobotInit()
{
Task myTask("image_process", imageProcessThread);
myTask.Start();
}
The thread function must return an int and take a variable number of arguments (up to 10), which is denoted in C/C++ by “…” as the last function argument.
Your task will run from start to finish once, after Start is called. If you don’t want it to be deleted, then put a loop in it so it doesn’t return until you’re done:
int imageProcessThread(...)
{
va_arg argptr;
// do stuff...
}
To get access to any of your 10 arguments, you must use the va_arg macros, which are explained here:
http://www.cppreference.com/wiki/c/other/va_arg
If you are using shared data between threads, you must be sure to enforce synchronization between the threads. WPILib has an interesting abstraction for synchronization with semaphores - examples are in the C++ Programming Guide - but it’s really more confusing in my opinion. PM me if you need help with synchronization.
Thanks for your help Shinigami. Here’s what I have found. If you start a task in an init function it is deleted when the init function ends. It appears the task thinks its a local object but when I try to put the definition as a global I get an error “error: expected ,' or
…’ before string constant”. Does anybody know how to make it global (I will experiment and post the answer if I figure it out.)
I’m having difficulty getting the small code sample to compile, Shinigami. Hopefully, you or someone else could lend a hand?
Here is what I currently have:
#include "WPILib.h"
/** TODO: Change this message.
* This is a demo program showing the use of the RobotBase class.
* The SimpleRobot class is the base of a robot application that will automatically call your
* Autonomous and OperatorControl methods at the right time as controlled by the switches on
* the driver station or the field controls.
*/
class Robot : public SimpleRobot
{
RobotDrive myRobot; // robot drive system
Task CameraThread;
public:
Robot(void): // these must be initialized in the same order
myRobot(1, 2), // as they are declared above.
CameraThread("camera_thread", imageProcessThread())
{
GetWatchdog().SetExpiration(0.1);
}
/**
* Drive left & right motors for 2 seconds then stop
*/
void Autonomous(void)
{
GetWatchdog().SetEnabled(false);
myRobot.Drive(0.5, 0.0); // drive forwards half speed
Wait(2.0); // for 2 seconds
myRobot.Drive(0.0, 0.0); // stop robot
}
void OperatorControl(void)
{
GetWatchdog().SetEnabled(true);
while (IsOperatorControl())
{
GetWatchdog().Feed(); //woof.
}
}
int imageProcessThread(...)
{
// do stuff...
return 1;
}
};
START_ROBOT_CLASS(SimpleRobot);
Thanks.
Chief Pride,
I can see two small problems with your code, both of which are very easy to fix. The first:
When you pass a function as an argument, you don’t use parenthesis after the thread - parenthesis indicate a function call, not the function itself. So it should be just
CameraThread("camera_thread", imageProcessThread)
Secondly, your task function (imageProcessThread) must be declared outside any class definition. So move it after the class ends and before START_ROBOT_CLASS.
You may also have to put a “prototype” of your function before your class definition to make the compiler happy, like so:
int imageProcessThread(...); /* prototype */
class Robot : public SimpleRobot {
// ...
};
int imageProcessThread(...)
{
return 1;
}
START_ROBOT_CLASS(SimpleRobot);
Good luck and let me know if you have any more trouble.
Thank you very much, Shinigami.
Although, if you have a minute, would you mind letting me know why the prototype makes the compiler happy?
Thanks.
The compiler compiles the source code from top to bottom, so if you have a source file like :
test_function();
void test_function(void)
{ //do stuff
}
it is best to prototype “test_function” before you call it. This lets the compiler know that there is a definition of the function. Some compilers might not compile the source code without the prototypes, others might throw a “implicit reference” warning.
There is a good example of how to utilize tasks in WPILib source. Check out StartCameraTask in the AxisCam.cpp file.
here is a brief overview:
#include...
Task tsk("myTask",MyTask);//creates task "tsk" identified by the name "myTask" on the cRIO, calling function MyTask
//put variables to be accesed by the task and norm. code here
RobotDrive myRobot(1,2);
class ...
...
void Auto()
{
while (!tsk.IsReady())
{ }
tsk.Start(1);//start MyFunction on another thread w/ args (1);
while (IsAuto())
{
}
tsk.Stop();
}
...
...
};//end of class
void MyFunction (int arg1)
{
//code using arg1
}
You can have up to 10 int args, and the function must be global