Depends on a function and how much control you have over it.
In case of recv call you could use setsocketopt with SO_RCVTIMEO to set the timeout. The function call would return EAGAIN or EWOULDBLOCK in that case.
Alternatively, you could interrupt the recv call - the ways to do it are described at How to cleanly interrupt a thread blocking on a recv call?
In a more generic case, you could have start a parallel thread, and have both of them threads keep a reference to a boolean value that would mark if the timeout had expired. The original thread doing the work would need to periodically check it, and the other one would mark it after timeout has passed. If the function call finishes before the timeout, it would be main thread's responsibility to shutdown the helper.
In pseudocode it would look like this:
shared mutable state:
job_to_do = true
timeout_happened = false
main thread:
pthread_create(helper, ...)
/* we depend on the fact that 'job_to_do' will be set to false when there's nothing more to process */
while (job_to_do && !timeout_happened) {
process_more_for_some_time /* this obviously has to take less time than timeout */
}
if (job_to_do) {
perror("timeout")
}
helper thread:
time_passed = 0
while (job_to_do && time_passed < timeout) {
sleep(sample)
time_passed += sample
}
/* there's no point in signalling timeout if the job has finished */
if (job_to_do)
timeout_happened = true
Implementation detail: job_to_do and timeout_happened have to be atomic/visible, as you could be e.g. accessing the variable from different cores.