'Events' in the C world tend to be done through function pointers, i.e. you pass a function pointer to the function that starts a task, and it will be called when the task is complete.
extern int start_something(void (*f)()) {
(*f)();
}
Sometimes the function pointer is stored in a structure or registered with a single function and then used in response to others, but the idea is the same.
Through P/Invoke you can pass a delegate to functions with this type of signature, i.e.
[DllImport(...)]
public int start_something(VoidDelegate f);
public delegate void VoidDelegate();
(Apologies if I forgot how to write function pointers in C, it's been a long, long time :P.)
edit: updated C sample