---
title: "Work queues"
canonical_url: https://developer.repebble.com/pebbleos/docs/samples/kernel/work/
last_updated: 2026-11-13
sdk_version: 4.44
---
# Work queues

Source: https://developer.repebble.com/pebbleos/docs/samples/kernel/work/

This sample defers work to a [work queue](https://developer.repebble.com/pebbleos/docs/kernel/work.md): first to the system’s, then to one it creates. The work item is part of the object it acts on, a pretend sensor, and its function handles every event since its last run.

Three submits made one run: an item is queued at most once, which is why the function drains a count instead of assuming one run per event. The canceled item never ran, so its event stays pending for the next submit.

Run:

`pbl samples samples/kernel/work`

Boards:

every board

## Sources

src/main.c

```
#include \<pbl/kernel/thread.h\>#include \<pbl/kernel/work.h\>#include \<pbl/logging/logging.h\>#include \<pbl/util/misc.h\>/\* A work item lives in the object it acts on, which its function gets back. \*/struct sensor {const char \*name;unsigned int pending\_events;unsigned int runs;struct pbl\_work work;};static void prv\_sensor\_work(struct pbl\_work \*work) {struct sensor \*sensor = container\_of(work, struct sensor, work);/\* One run serves every event since the last one, however often it was submitted. \*/PBL\_LOG\_INFO("%s: handling %u events on %s", sensor-\>name, sensor-\>pending\_events,pbl\_thread\_name(pbl\_thread\_current()));sensor-\>pending\_events = 0;sensor-\>runs++;}static void prv\_sensor\_event(struct pbl\_workq \*q, struct sensor \*sensor) {sensor-\>pending\_events++;if (!pbl\_work\_submit(q, &sensor-\>work)) {PBL\_LOG\_INFO("%s: already pending, not queued again", sensor-\>name);}}static struct sensor s\_accel = {.name = "accel", .work = PBL\_WORK\_INITIALIZER(prv\_sensor\_work)};static struct sensor s\_touch = {.name = "touch", .work = PBL\_WORK\_INITIALIZER(prv\_sensor\_work)};/\* A queue of its own keeps slow work from delaying the system's. \*/static PBL\_WORKQ\_DEFINE(s\_sensor\_q);PBL\_THREAD\_STACK\_DEFINE(s\_sensor\_q\_stack, 1024);static struct pbl\_thread s\_sensor\_q\_thread;int main(void) {const struct pbl\_thread\_attr attr = {.name = "sensor\_q",.entry = pbl\_workq\_thread,.arg = &s\_sensor\_q,.prio = CONFIG\_KERNEL\_MAIN\_THREAD\_PRIO - 1,.privileged = true,.stack = s\_sensor\_q\_stack,.stack\_size = sizeof(s\_sensor\_q\_stack),};/\* Both queues run below main, so nothing runs until main waits for them. \*/PBL\_LOG\_INFO("main: three accel events for the system queue");for (unsigned int i = 0; i \< 3; i++) {prv\_sensor\_event(&pbl\_sys\_workq, &s\_accel);}pbl\_workq\_flush(&pbl\_sys\_workq);PBL\_LOG\_INFO("main: accel work ran %u time(s)", s\_accel.runs);PBL\_LOG\_INFO("main: touch and accel events for a queue of our own");pbl\_thread\_create(&s\_sensor\_q\_thread, &attr);prv\_sensor\_event(&s\_sensor\_q, &s\_touch);prv\_sensor\_event(&s\_sensor\_q, &s\_accel);pbl\_workq\_flush(&s\_sensor\_q);PBL\_LOG\_INFO("main: a touch event, canceled before the queue gets to it");prv\_sensor\_event(&s\_sensor\_q, &s\_touch);if (pbl\_work\_cancel\_sync(&s\_touch.work)) {PBL\_LOG\_INFO("main: touch work was pending and will not run");}pbl\_workq\_flush(&s\_sensor\_q);PBL\_LOG\_INFO("main: touch work ran %u time(s)", s\_touch.runs);PBL\_LOG\_INFO("Sample done");return 0;}
```

## Output

```
accel: already pending, not queued again
accel: already pending, not queued again
accel: handling 3 events on SysWorkq
main: accel work ran 1 time\(s\)
touch: handling 1 events on sensor_q
accel: handling 1 events on sensor_q
main: touch work was pending and will not run
main: touch work ran 1 time\(s\)
Sample done
```

Generated from PebbleOS [f4926c952](https://github.com/coredevices/pebbleos/commit/f4926c952bf9b82bce9e3cdb44645a59531c0ee9). This page is maintained in the pebbleos repository: [docs/samples/kernel/work.md](https://github.com/coredevices/pebbleos/blob/f4926c952bf9b82bce9e3cdb44645a59531c0ee9/docs/samples/kernel/work.md).
