Cold Help System: Programming: ColdC Reference Manual: Implementation: Tasks and Frames: Preempting: Example


An example of suspending a task is when reading an indefinite amount of input from a connection. Input arrives through the parse method on an object (see Networking), which we define as follows, assuming the object variables reading, read, buffer and lines. reading is used to store a boolean value of true or false, depending upon if we are reading input or not. read is used to store what we have already read from the connection. buffer is used to store incoming information which is not yet parsable by the function buf_to_strings() (i.e. there is no carriage return yet). lines is used to buffer lines converted by buf_to_strings() from the connection which we have not parsed yet. It is important to use an object variable for both buffer and lines, because if the task suspends all information stored in either variable would be suspended along with that instance of the task.

driver method .parse() {
    arg incoming;
    var line;

    lines = buf_to_strings(buffer + incoming));
    buffer = lines[listlen(lines)];
    lines = delete(lines, listlen(lines));

    // now parse the lines
    for line in (buf_to_strings(incoming)) {
        if (reading) {
            if (line == ".")
                .done_reading();
            else
                read += [line];
        } else {
            .parse_line(line);
        }
    }
}

We will not define the method parse_line, just assume that it parses the line as a command. When an object wishes to start reading from the connection it calls the method .read() on the connection object:

public method .read() {
    // reading just has to be true, so lets save space and store the
    // task id there as well, instead of storing it in another variable.
    reading = task_id();

    // make sure this is an empty list
    read = [];

    // suspend the task, have our return value be the return value
    // of suspend (which is whatever resume() sends)
    return suspend();
}

When a period is found as the line being read, the connection is done reading (the period is insignificant, and is only used in this example for convenience), and the method done_reading is called:

protected method .done_reading() {
    var info, task;

    // get a local copy of what we read, and the task id
    info = read;
    task = reading;

    // reset the object variables first
    read = [];
    reading = 0;

    // resume the task, send what we read as the return
    // value for suspend()
    resume(task, info);
}

Now, all that has to happen to read input from a connection is to call the method .read() on the connection object, and the input read is returned from the method call.

It is possible to set a task as atomic. Atomic tasks cannot be preempted or suspended. If an attempt is made to preempt or suspend an atomic task the error ~atomic is thrown instead. However, calling refresh() while executing atomically will always refresh the current frame's ticks. A task's atomic state is toggled using the function atomic().

Note: be very cautious when using atomic tasks. Atomic tasks can easilly disrupt the regular integrity of an online environment. See the section on Security.


the Cold Dark