Home | Projects | Notesk > Multi-Threading (POSIX Threads) > Notification Chains (NFC)
Notification Chain is an architectural concept (i.e., can be implemented in many other programming languages) used to notify multiple subscribers that are interested in a particular event. Basically, it is all about the communication between a publisher and the multiple subscribers.
A party which generates an event is called the Publisher, and the parties that are interested in being notified of the event are called Subscribers.
There is one publisher and multiple subscribers.
Once an event is generated/produced by the publisher, the event is pushed to the subscribers that are interested in it.
Subscribers can register and de-register for events at their will.
Publishers/subscribers could be any entities:
Multiple threads of the same process
Multiple processes running on the same system
Multiple processes running on the different systems
Different components of a big software system
NFC is a linked list of callbacks (function pointers).
xxxxxxxxxx
61/* structure for NFC */
2typedef struct notif_chain_
3{
4 char nfc_name[64]; /* optional */
5 glthread_t notif_chain_head; /* head of the linked list */
6} notif_chain_t;
Each element in NFC is called the notification chain element.
xxxxxxxxxx
121/* structure for notification chain elements */
2typedef struct notif_chain_elem_
3{
4 char key[MAX_NOTIV_KEY_SIZE]; /* 64 or 128 bytes will be sufficient */
5 size_t key_size;
6 bool_t is_key_set; /* user specified the key or not? (whild card user may not) */
7 nfc_app_cb app_cb; /* function pointer by which subscribers want to get notified */
8 glthread_t glue;
9} notif_chain_elem_t;
10
11/* prototype of the function pointer must be generic so that it works for all types of data for all types of subscribers */
12typedef void (*nfc_app_cb)(void *, size_t); /* 2nd arg: size of the 1st arg */
The following example of NFC implementation is completely generic and can be applied to any type of applications.
notif.h
xxxxxxxxxx
391/*
2 * File Name : notif.h
3 * Description : Interface for generic notification chain (NFC) infrastructure
4 * Author : Comments added by Kyungjae Lee (Original: Abhishek Sagar)
5 * Date Created : 12/29/2022
6 */
7
8
9
10
11/* size_t */
12
13
14
15
16
17typedef void (*nfc_app_cb)(void *, size_t);
18
19typedef struct notif_chain_elem_
20{
21 char key[MAX_NOTIV_KEY_SIZE]; /* 64 or 128 bytes will be sufficient */
22 size_t key_size;
23 bool_t is_key_set; /* user specified the key or not? (whild card user may not) */
24 nfc_app_cb app_cb; /* function pointer by which subscribers want to get notified */
25 glthread_t glue;
26} notif_chain_elem_t;
27
28typedef struct notif_chain_
29{
30 char nfc_name[64]; /* optional */
31 glthread_t notif_chain_head; /* head of the linked list */
32} notif_chain_t;
33
34void nfc_register_notif_chain(notif_chain_t *nfc, notif_chain_elem_t *nfce);
35void nfc_invoke_notif_chain(notif_chain_t *nfc,
36 void *arg, size_t arg_size,
37 char *key, size_t key_size);
38
39/* NOTIF_CHAIN */
notif.c
xxxxxxxxxx
651/*
2 * File Name : notif.c
3 * Description : Implementation of generic notification chain (NFC) infrastructure
4 * Author : Comments added by Kyungjae Lee (Original: Abhishek Sagar)
5 * Date Created : 12/29/2022
6 */
7
8
9
10
11
12
13void nfc_register_notif_chain(notif_chain_t *nfc, notif_chain_elem_t *nfce)
14{
15 /* subscriber already filled up the element to insert. just make a copy */
16 notif_chain_elem_t *new_nfce = calloc(1, sizeof(notif_chain_elem_t));
17 memcpy(new_nfce, nfce, sizeof(notif_chain_elem_t));
18
19 /* insert the new node into NFC */
20 glthread_add_next(&nfc->notif_chain_head, &new_nfc->glue);
21
22}
23
24/* function to be invoked by the publisher to notify the subscriber */
25/* publisher will traverse the entire linked list passed as the 1st arg, match each
26 notification element with the key, and if there's a match, the callback registered
27 to that element will be invoked as a means of notifying the subscriber */
28void nfc_invoke_notif_chain(notif_chain_t *nfc,
29 void *arg, size_t arg_size,
30 char *key, size_t key_size)
31{
32 /* iterate over the NFC elements */
33 glthread_t *curr;
34 notif_chain_elem_t *nfce;
35 assert(key_size <= MAX_NOTIF_KEY_SIZE);
36
37 ITERATE_GLTHREAD_BEGIN(&nfc->notif_chain_head, curr)
38 {
39 /* pick up the NFC element one by one */
40 nfce = glthread_glue_to_notif_chain_elem(curr);
41
42 /* handle the wild card NFC element */
43 if(!(key && key_size && nfce->is_key_set && (key_size == nfce->key_size)))
44 {
45 /* if the key is not specified OR if the key in the NFC element is not specified
46 (which essentially means that it is a wild card entry)
47 then, no matter what, the publisher should invoke the callback present in the
48 NFC element */
49 nfce->app_cb(arg, arg_size);
50
51 /* note that the publisher uses 'arg' and 'arg_size' passed by the subscriber when
52 notifying the subscriber */
53 }
54 /* handle the situation where the key has been specified */
55 else
56 {
57 if (memcmp(key, nfce->key, key_size) == 0)
58 {
59 /* invoke the callback only when the passed key matches the key in the NFC
60 element */
61 nfce->app_cb(arg, arg_size);
62 }
63 }
64 }ITERATE_GLTHREAD_BEGIN(&nfc->notif_chain_head, curr);
65}
You are free to implement any additional routines. e.g., Unregister or unsubscription function using which a subscriber can unsubscribe from the notification chain.
Sagar, A. (2022). Part A - Multithreading & Thread Synchronization - Pthreads [Video file]. Retrieved from https://www.udemy.com/course/multithreading_parta/