TaskTurner first code

Originally published April 27, 2017 dougwihau on this blog.

Revised and republished on a new host, May 21, 2024.

The first code


#include "stdio.h"
#include "../include/errors.h"
#include "../include/tasks.h"
#include "../include/taskrunner.h"

int doNow, doLater;

int taskrunner(Task * TaskList, unsigned int listLen)
	int iter;

	printf("Running Tasks, %d\n", listLen);
	for(iter = 0; iter < listLen; iter++)
		if( 0 == *TaskList[iter].runNow)
			printf("%s, %d\n", TaskList[iter].taskName, *TaskList[iter].runNow);

Task tasks[] = {
	{"First_Task", &doNow},
	{"Second_Task", &doLater},
	{"Third_Task", &doNow},

#define NUM_TASKS sizeof(tasks)/sizeof(Task)

int runAllTasks(void)
	int Error;
	Error = 0;
	doNow = 0;
	doLater = 0;
	while(0 == Error)
		Error = taskrunner(tasks, NUM_TASKS);
		if(doLater == 0)
			Error = 0;
		doLater = 1;

int main()
	int Error;
	printf("Hello world\n");
	/* Initialize task list */
	/* Run the task list using the given tasks */
	printf("Final task result = %d\n", runAllTasks());

Given there is not a whole lot going on here, but let me point out a few things worth noticing.

  • First of all, I have a working directory with the include files separate from the C code. This keeps things clean and neat for the future. I am also a big fan on one include for the interface to a file, and never put an include inside an include. Yes, then the order of include files matters. You will thank me when the project gets big and compile times stay short.
  • I put the main() function inside the one file to get started quickly.
  • The main is calling runAllTasks() which passes a made up, dummy task list into the taskRunner function. Seems simple, and gets things working here.
  • The typedef for the Task structure is right, as are the types and the pointer and array being passed in. That can be tricky, but once it is correct, no worries.
  • The size of the array is automatically calculated based on the number of items in the array and the structure. This will always be correct. There is no need to keep track of the array position or use an enumeration for each task. Tasks have names, but if that takes up too much space, it can be changed. (It should probably be a char * pointing at the string.) The divide of two “sizeof()” operations will happen at compile time. The value used at run time is a constant. No performance problems here.
  • There is enough test code that the two ‘if’ statements have been tested. The conditional running of tasks works, and the error handling to break out of the loop works. We have a start on unit testing.
  • The whole thing is debugged with simple printf statements.

Still, a lot to do

This is very basic. You get the idea here. We will keep the tasks in a table, then let the task runner run each task for us. This structure keeps the tasks small and independent. There are a couple more cool tricks we will introduce as we go.

The types are all standard C types. In a real system we would use sized types, like int16_t or uint16_t. The standard types make it easy for you to build and try, and quick to get moving.

Quick, get started

The code you see took about 35 minutes to code up and build. It is a directory on my Linux machine. I don’t even have a makefile at this point, I am just doing ‘cc src/runtask.c’ and it builds.

dougg:tasker$ cc src/runtask.c
dougg:tasker$ ls
a.out include src test
dougg:tasker$ ./a.out
Hello world
Running Tasks, 3
First_Task, 0
Second_Task, 0
Third_Task, 0
Running Tasks, 3
First_Task, 0
Third_Task, 0
Final task result = 3

And, best of all, it works.

What do you think? Please let me know in the comments.







Leave a Reply

Your email address will not be published. Required fields are marked *