cthread

cthread (ControllableThread) is a Python library that is built upon the threading.Thread class. cthread provides additional functionality to the standard threading.Thread library by allowing the threads to be started, paused, resumed, reset, and killed.

Installation

For Python 2/3:

>>> pip install cthread

Usage

See the Quickstart and Alternative States examples listed in Examples.

Module (cthread)

The documentation of the cthread package is outlined below.

Exceptions

The custom exceptions that cthread can raise are documented below.

exception cthread.CThreadException(message=None, *args, **kwargs)[source]

Bases: Exception

Base class of any ControllableThread exception.

All exceptions that are thrown by the cthread module inherit from this exception. This specific exception instance is however never raised.

Parameters

message (str, optional) – Information about the exception that was raised.

exception cthread.CallbackNotImplemented(message=None, *args, **kwargs)[source]

Bases: cthread.cthread.CThreadException

A state callback function has not been implemented by the child class.

This exception is raised if a cthread.ControllableThread is created without overwriting a particular state callback function.

Parameters

message (str, optional) – Information about the exception that was raised.

exception cthread.InvalidArgument(message=None, *args, **kwargs)[source]

Bases: cthread.cthread.CThreadException

Base class of any invalid argument exception.

This exception is raised if an invalid argument is input to any publicly accessible cthread method. This specific exception instance is however never raised.

Parameters

message (str, optional) – Information about the exception that was raised.

exception cthread.InvalidState(message=None, *args, **kwargs)[source]

Bases: cthread.cthread.InvalidArgument

Base class of an unrecognised thread state.

This exception is raised if a thread state is not recognised. While this exception is a base class of an unrecognised thread state, this specific instance could also be raised.

Parameters

message (str, optional) – Information about the exception that was raised.

exception cthread.InvalidMaxState(message=None, *args, **kwargs)[source]

Bases: cthread.cthread.InvalidState

Maximum thread state is not recognised.

This exception is raised if the maximum thread state is not recognised.

Parameters

message (str, optional) – Information about the exception that was raised.

exception cthread.InvalidAlternativeState(message=None, *args, **kwargs)[source]

Bases: cthread.cthread.InvalidState

Alternative thread state is not recognised.

This exception is raised if the required updated state of the thread is not a registered alternative state.

Parameters

message (str, optional) – Information about the exception that was raised.

exception cthread.InvalidCallback(message=None, *args, **kwargs)[source]

Bases: cthread.cthread.InvalidArgument

No alternative state callback functions supplied.

This exception is raised if the thread is initialised with alternative states but not alternative state callback functions.

Parameters

message (str, optional) – Information about the exception that was raised.

exception cthread.InvalidName(message=None, *args, **kwargs)[source]

Bases: cthread.cthread.InvalidArgument

Desired name of the thread is not a string.

This exception is raised if the name of the thread is not a string.

Parameters

message (str, optional) – Information about the exception that was raised.

exception cthread.InvalidQueue(message=None, *args, **kwargs)[source]

Bases: cthread.cthread.InvalidArgument

No communication method to the initialising thread.

This exception is raised if an instance of a cthread.ControllableThread is initialised without a means of communicating with the thread that initialises it.

Parameters

message (str, optional) – Information about the exception that was raised.

Classes

The classes contained within the cthread package are documented below.

class cthread.ControllableThread(name, queue, **kwargs)[source]

Bases: threading.Thread

Parent class for any cthread.ControllableThread.

Allows threads to be killed, paused and resumed, and allows for direct communication to the main initialising thread.

Parameters
  • name (str) – Name of the thread.

  • queue (queue.Queue) – Priority queue for communication to the main thread.

Raises
alt(name)[source]

Updates the state of the thread to a registered alternative state.

Note that the state must be a registered alternative state in order for the thread to be updated to the desired state.

Parameters

name (str) – Name of the state to which the thread will be updated.

Raises

cthread.InvalidAlternativeState – If the required updated state of the thread is not a registered alternative state.

kill()[source]

Updates the state of the thread to ThreadState.KILLED.

pause()[source]

Updates the state of the thread to ThreadState.PAUSED.

reset()[source]

Updates the state of the thread to ThreadState.STARTED.

resume()[source]

Updates the state of the thread to ThreadState.RESUMED.

run()[source]

Entry point for the thread.

Contains the cyclic executive of the thread. There are at least six possible states for the thread:

  1. STARTED

  2. ACTIVE

  3. IDLE

  4. PAUSED

  5. RESUMED

  6. KILLED

  7. Any alternative individual thread-specific states.

Each of these states has a callback function that must be implemented in any of the child threads. Of course, the alterative state callback should not be implemented if there are no alternative states.

This cyclic executive will execute as long as the thread is not killed.

Raises

cthread.CallbackNotImplemented – If any of the following callback functions were not overwritten: cthread.ControllableThread._started_callback(), cthread.ControllableThread._active_callback(), cthread.ControllableThread._paused_callback(), cthread.ControllableThread._resumed_callback(), or cthread.ControllableThread._killed_callback().

class cthread.ThreadState[source]

Bases: object

Represents the state of the thread.

STARTED

Numerical encoding of the ‘started’ thread state.

Type

int

ACTIVE

Numerical encoding of the ‘active’ thread state.

Type

int

IDLE

Numerical encoding of the ‘idle’ thread state.

Type

int

PAUSED

Numerical encoding of the ‘paused’ thread state.

Type

int

RESUMED

Numerical encoding of the ‘resumed’ thread state.

Type

int

KILLED

Numerical encoding of the ‘killed’ thread state.

Type

int

get_state()[source]

Gets the state of the thread.

Returns

State of the thread. There are at least six possible return values:

Return type

int

update_max_state(maxState)[source]

Updates the maximum state of the thread.

The maxState value is used to determine the validity of a state to supplied to the cthread.ThreadState.update_state() function. The state of the thread must be within a predefined range, or else it is an invalid state. The maxState is also not a fixed constant because the user can define their own states, and hence the validity check of a state must accomodate these user-defined states.

Parameters

maxState (int) – Maximum state that the thread can take.

Raises

cthread.InvalidState – If the maximum state is <= ThreadState.KILLED.

update_state(state)[source]

Updates the state of the thread.

Parameters

state (int) – New state of the thread.

Raises

cthread.InvalidState – If state < ThreadState.STARTED or state > ThreadState._maxState

Examples

Note

In order for the cthread package to be fully functional, the developer must follow two coding practices:

  1. Any code within the cthread.ControllableThread._active_callback() callback function and any registered alternative state callback function must be:

    • Non-blocking (at the very least it must only block for a short period of time), and

    • Contain no indefinite while or for loops.

    In short, the cthread.ControllableThread._active_callback() callback function and any registered alternative state callback functions must be written to minimize its execution time. This allows the thread to be controllable. This is because it is only at the end of each callback function that a check is conducted to determine whether the state of the thread must be updated.

  2. The code within the cthread.ControllableThread._started_callback() cthread.ControllableThread._paused_callback(), cthread.ControllableThread._resumed_callback(), and cthread.ControllableThread._killed_callback() callback functions will only execute once. There is a wrapper function for each callback function within the cthread.ControllableThread class. This wrapper function automatically updates the thread state to cthread.ThreadState.ACTIVE at the completion of the cthread.ControllableThread._started_callback() and cthread.ControllableThread._resumed_callback() callback functions, and cthread.ThreadState.IDLE at the completion of the cthread.ControllableThread._paused_callback() callback function. These callbacks should be written in such a way that they pause or resume/start thread functionality.

Quickstart

This code example can be found in the file examples/quickstart.py. It is an example of how to create a class that inherits from ControllableThread. No functionality has been added to any of the states. The lines:

1
2
        # Add any state specific code here (and remove the 'pass') #
        pass

can be replaced in each of the state callback functions with functional state code that is specific to the user’s needs.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import cthread
import logging
import queue as q
import time

# Configure the logger #
logging.basicConfig(level=logging.INFO,
        format='%(asctime)s %(levelname)s %(name)s %(message)s',
        datefmt='%Y-%m-%d %H:%M:%S')

class Quickstart(cthread.ControllableThread):

    def _started_callback(self):
        # Add any state specific code here (and remove the 'pass') #
        pass

    def _active_callback(self):
        # Add any state specific code here (and remove the 'pass') #
        pass

    def _paused_callback(self):
        # Add any state specific code here (and remove the 'pass') #
        pass

    def _resumed_callback(self):
        # Add any state specific code here (and remove the 'pass') #
        pass

    def _killed_callback(self):
        # Add any state specific code here (and remove the 'pass') #
        pass

if __name__ == "__main__":

    queue = q.PriorityQueue()
    quickstart = Quickstart(name="QuickstartThread", queue=queue)

    quickstart.start() # Start the thread.  MUST be called first #
    time.sleep(1)

    quickstart.pause() # Pause the thread. #
    time.sleep(1)

    quickstart.resume() # Resume the thread #
    time.sleep(1)

    quickstart.reset() # Reset the thread #
    time.sleep(1)

    quickstart.kill() # Kill the thread #

This code gives the following output:

>> Starting thread: QuickstartThread...
>> (Re)initialising thread...
>> Thread activated!
>> Pausing thread...
>> Thread paused!
>> Resuming thread...
>> Thread activated!
>> (Re)initialising thread...
>> Thread activated!
>> Killing thread...
>> Stopped thread: QuickstartThread!

Alternative Thread states

This code example can be found in the file examples/alternative_state.py. It is an example of how to create a class that inherits from ControllableThread with additional allowable thread states. No functionality has been added to any of the additional states. The lines:

1
2
        # 2. Add any alternative state specific code here #
        pass

can be replaced in each of the additional state callback functions with functional state code that is specific to the user’s needs.

Note

There are two steps that must be followed when creating a cthread.ControllableThread instance with alternative states:

  1. Initialise the cthread.ControllableThread parent class with additional kwargs of the form name: callback. Each state name and callback function must be unique.

  2. Supply a callback function for each alternative state with the same name as that which was passed to the parent class in step 1 above.

These two steps are highlighted in the proceeding code.

Then, in order to transition the thread into one of the alternative states, the public method cthread.ControllableThread.run() must be called with the name parameter identical to the name specified in the kwargs from step 1 above.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import cthread
import logging
import queue as q
import time

# Configure the logger #
logging.basicConfig(level=logging.INFO,
        format='%(asctime)s %(levelname)s %(name)s %(message)s',
        datefmt='%Y-%m-%d %H:%M:%S')

class AlternativeState(cthread.ControllableThread):

    def __init__(self, queue):
        # 1. Initialise ControllableThread with additional kwargs #
        cthread.ControllableThread.__init__(self,
                name="AlternativeStateThread",
                queue=queue,
                ALT1=self._alt1_callback,
                ALT2=self._alt2_callback
        )

    def _started_callback(self):
        pass

    def _active_callback(self):
        pass

    def _paused_callback(self):
        pass

    def _resumed_callback(self):
        pass

    def _killed_callback(self):
        pass

    def _alt1_callback(self):
        # 2. Add any alternative state specific code here #
        pass

    def _alt2_callback(self):
        # 2. Add any alternative state specific code here #
        pass

if __name__ == "__main__":

    queue = q.PriorityQueue()
    quickstart = AlternativeState(queue)

    quickstart.start() # Start the thread.  MUST be called first #
    time.sleep(1)

    quickstart.alt(name="ALT1") # ALT1 state #
    time.sleep(1)

    quickstart.alt(name="ALT2") # ALT2 state #
    time.sleep(1)

    quickstart.kill() # Kill the thread #

This code gives the following output:

>> Starting thread: Starting thread: AlternativeStateThread...
>> (Re)initialising thread...
>> Thread activated!
>> Transitioning thread to ALT1 state...
>> Transitioning thread to ALT2 state....
>> Killing thread...
>> Stopped thread: AlternativeStateThread!

MIT License

Copyright (c) 2019 ksonter95

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Change Log

1.2.1 (2019-05-08)

Features
  • Added the additional classes to the package (imported into __init__.py) that were released as part of version 1.2.

1.2 (2019-05-07)

Features
  • Added examples

  • Added wrapper functions to the callback functions for logging purposes and automatic state transition purposes

  • Added alternative state registration process

  • Additional exceptions

1.1 (2019-05-07)

Features
  • Updated Google docstrings to be compatible with Sphinx RST formatting.

  • Finalised documentation for the package classes and exceptions.

1.0 (2019-05-05)

Features
  • Removed time delay in the cyclic executive of the thread.

0.0.1 (2019-05-01)

Features
  • Initial release

Indices and tables