Call a function periodically within a thread in C - c

I'm writing a program in C which connects to a camcorder via wifi and can control zoom, start and stop recording when the user wants to execute these functions.
After the initial connect to the camcorder, I will have to send a Session Refresh Command every 5 seconds. So my idea was to start a new thread after the initial connect which sends the refresh command every 5 seconds.Something like,
while(1) {
sendRefreshCommand();
usleep(5000000);
}
Is this idea ok, or is there any other way to achieve that?
Edit: Here is my code so far to illustrate a little bit what I want to do. The user is permanently asked what he wants to do. This is for testing purposes only. Later on the zoom and recording commands will be performed by the program automatically. Parallel to asking the user the session has to be refreshed every 5 seconds.
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include "camctrl.h"
extern struct conf g_Config;
void* sessionContinueThread(void *session_args){
while(1){
sessionContinue(g_Config.cam_ip);
usleep(3000000);
}
}
int main(){
int sel;
pthread_t session_thread;
void *arg2;
readConfig("config2.json");
ConnectToCam(g_Config.cam_ip);
arg2 = (void *) g_Config.cam_ip;
pthread_create( &session_thread , NULL , sessionContinueThread , arg2 );
pthread_join(session_thread,NULL);
while(1){
printf("\n[0] Zoom Tele\n");
printf("[1] Zoom Wide\n");
printf("[2] Start Recording\n");
printf("[3] Stop Recording\n");
printf("[4] Session Continue\n");
printf("[5]Stop\n");
printf("Selection: ");
scanf("%d",&sel);
switch( sel ){
case 0: zoomTele(); break;
case 1: zoomWide(); break;
case 2: RecStart(); break;
case 3: RecStop(); break;
case 4: sessionContinue(g_Config.cam_ip); break;
case 5: exit(0); break;
default: break;
}
}
return 0;
}

Generally this is OK. But there are some considerations you should think about:
You have to synchronize the access to your transmission channel in order to not get some very weird, hard to trace and reproduce effects
Don't set the timeout for the refresh command exactly to 5s, take e.g. the half or a few percent lower than 5s. Otherwise you'll possibly suffer from effects that arise from jitter. (e.g. if the timebase of your camcorder is about as accurate as the timebase of your PC, the camcorder will get the "keep alive" message after 5s + transmission time if you send the request after 5s. This would be a timeout then.
Think about introducing a gate keeper thread or object to serialize the access to your communication channel. This would give you some opportunities to optimize. For example, I could imagine, that you don't have to send the keep-alive if you just issued a command.
Don't start the thread with while(1). Hand the thread a reference to a value or an event object that allows you to signal the thread it should be terminated. This gives you the opportunity to clean up everything properly when shutting down your program.
If you want me to explain some of the considerations further, let me know.
EDIT: Further explaination to #4:
You should take care that you clean up every resource you allocate. Of course you can rely on the OS that it's possibly cleaning up threads and stuff when it throws your process out of the memory, but that's not really a good way to go.
So after you creating your thread and running your program, you should also destroy your thread when the program will exit. To do so you can of course invoke some calls that terminate the thread immediately. The downside of that is, that you can happen to leave some things (e.g. mutexes) in undefined state.
What does this mean? Imagine the thread took the mutex, was about to send something and exactly at that point in time your main thread terminates the thread. In this case your mutex might remain locked, and everyone else is unable to aquire it. (e.g. to send a session destroy command).
So the solution to avoid such things is to request the thread to terminate rather than forcing the termination from outside. The request leaves the thread the chance to cleanup things he possibly allocated or acquired and then exit. The thread requesting the other thread to terminate should wait for the other thread before exiting himself (using kind of a join function).

Your idea is looking good. You can achieve same by using alarm signal and signal handlers. Initialize a signal handler for alarm signal and rise alarm signal by passing 5 as argument. After 5 seconds your process receives a sigalarm signal and it invokes signal handler of sigalrm. In signal handler send refresh command and again raise sigalrm for 5 seconds. This loops continuously works. But thing is your main program execution is halted every time it receives a sigalrm

Related

Cancelling calculation early using pthreads

I have a program in c where I want to do some calculations which may or may not take a very long time. It is hard to know beforehand how much time the calculations will take. The program has a cli so right now I usually do something like this
./program
do calculation 243
and it starts calculating. If I want to cancel it because it takes to much time I do ctrl+c and restart the program with another calculation. Now I would like for the program to cancel the calculation itself after either q has been pressed or for example 10 seconds has passed.
I have found a way which seems to do what I expect using pthreads. I'm however wondering if this is recommended or if there are for example any memory leaks or other things that can happen.
The following is my code
void *pthread_getc(void *ptr) {
char c = '\0';
while (c != 'q')
c = getc(stdin);
pthread_cancel((pthread_t)ptr);
}
void *pthread_sleep(void *ptr) {
sleep(10);
pthread_cancel((pthread_t)ptr);
}
void pthread_cancellable(void *(*ptr)(void *), struct arg *arg) {
pthread_t thread_main, thread_getc, thread_sleep;
pthread_create(&thread_main, NULL, ptr, (void *)arg);
pthread_create(&thread_getc, NULL, pthread_getc, (void *)thread_main);
pthread_create(&thread_sleep, NULL, pthread_sleep, (void *)thread_main);
pthread_join(thread_main, NULL);
pthread_cancel(thread_getc);
pthread_cancel(thread_sleep);
pthread_join(thread_getc, NULL);
pthread_join(thread_sleep, NULL);
}
the idea being that both pthread_getc and pthread_sleep can cancel main, and once main is cancelled so are these two. Then I simply call pthread_cancellable where the first argument is a function doing the calculation and the second argument is the arguments to the calculating function.
Can something go wrong with memory leaks here or something else? Is there an easier/better way to this in c?
What happens if main is cancelled two times and if a thread gets cancelled when its already done?
Can something go wrong with memory leaks here or something else?
If the program is going to terminate after aborting the computation then there is no issue with memory leaks. The system does not rely on processes to clean up after themselves -- it will reclaim all memory allotted to the process no matter how the process used it.
But your code violates the #1 rule of pthread_cancel(): never call pthread_cancel(). And although monitoring stdin for a q keystroke could work, that's a bit odd, and it potentially gets in the way of using stdin for something else you want to add to your program later.
Is there an easier/better way to this in c?
Yes. In the first place, if the objective is simply to terminate the program at timeout / user interrupt, then do that. That is is, have any thread call exit() when you want to terminate. You do not need to cancel any threads for that.
In the second place, I don't see what is gained by implementing a custom keyboard action (type 'q' to abort) when the standard interrupt signal sent by Ctrl-C works fine, and you even get the latter for free. If you want or need to perform some kind of extra behavior in response to an interrupt signal (before or instead of terminating), then register a handler for it.
There are multiple ways you could implement the early termination behavior, but here are outlines of two I like:
No-frills abortion upon timeout (or Ctrl-C):
Only the program's initial thread is needed.
Before it launches the computation, it creates and starts an interval timer (timer_create()) to count down the timeout. Configure the timer to raise SIGINT when it expires.
That's it. You get termination via the keyboard (albeit with Ctrl-C as you already do, not 'q') and the same termination behavior as far as an external observer can see in the event of a timeout.
optional addition 1:
If desired, you can install a handler for SIGINT to get extra or different behavior upon cancellation than you otherwise would. Note, however, that there are significant limits on what a signal handler may do. For example, maybe you want to emit a message to stderr (use write(), not fprintf() for such things), or you want to exit() with non-zero status instead of terminating (directly) because of the signal.
optional addition 2:
If the program reaches a point where it is not finished but it no longer wants to be terminated when the timeout is reached then it may at that point use timer_delete() to disable the timer.
With-frills abortion upon timeout (or Ctrl-C):
If you want to perform work in response to abort of the computation that is unsuited for a signal handler (too much, needs to call functions that are not async-signal-safe, ...) then you need a thread to do that in, and additional control structures and mechanisms. This is one way to do it:
Create and initialize a mutex, a condition variable, and a flag of type sig_atomic_t, all at file scope. The contract for these is that the flag may be accessed (read or write) only by a thread that currently holds the mutex locked, and that the mutex is the same that will be associated with all waits on the CV.
Install a signal handler for SIGINT that
locks the mutex
Provided that the flag does not indicate completion, updates it to indicate cancellation
unlocks the mutex
broadcasts to the CV
The last thing the computational thread will do after completing its work is (with the mutex locked) set the flag to a value indicating completion, and then broadcast to the CV.
The initial thread will then do this:
Setup as described in the previous points
lock the mutex
Create / start an interval timer (timer_create()) that raises SIGINT when it expires, after the chosen timeout period.
Start the computational thread
loop while the flag indicates ongoing computation. In the loop body
perform a wait on the CV
The computation having either completed successfully or been canceled at this point, perform whatever final actions are appropriate and then terminate, either by returning from main() or by calling exit().
That's still pretty clean, gets you both timeout-based and keyboard-based cancellation (albeit the latter with Ctrl-C instead of 'q'), puts all the cancellation handling in one place, and requires only one thread in addition to the computational one.
optional addition: abort in response to 'q'
Although I do not recommend it, if you really must have that termination by typing 'q', then you can set up another thread that monitors for that keypress / character, and performs a raise(SIGINT) if it sees it.

Correct way to unblock a kernel thread

There are linux kernel threads that do some work every now and then, then either go to sleep or block on a semaphore. They can be in this state for several seconds - quite a long time for a thread.
If threads need to be stopped for some reason, at least if unloading the driver they belong to, I am looking for a way to get them out of sleep or out of the semaphore without waiting the whole sleep time or triggering the semaphore as often as required.
I found and read a lot about this but there are multiple advises and I am still not sure how things work. So if you could shed some light on that.
msleep_interruptible
What is able to interrupt that?
down_interruptible
This semaphore function implies interrupt-ability. Same here, what can interrupt this semaphore?
kthread_stop
It's described as sets kthread_should_stop to true and wakes it... but this function blocks until the sleep time is over (even if using msleep_interruptible) or the semaphore is triggered.
What am I understanding wrong?
Use a signal to unblock - really?
My search found a signal can interrupt the thread. Other hits say a signal is not the best way to operate on threads.
If a signal is the best choice - which signal do I use to unblock the thread but not mess it up too much?
SIGINT is a termination signal - I don't intend to terminate something, just make it go on.
More information
The threads run a loop that checks a termination flag, does some work and then block in a sleep or a semaphore. They are used for
Situation 1.
A producer-consumer scenario that uses semaphores to synchronize producer and consumer. They work perfectly to make threads wait for work and start running on setting the semaphore.
Currently I'm setting a termination flag, then setting the semaphore up. This unblocks the thread which then checks the flag and terminates. This isn't my major problem. Hovever of course I'd like to know about a better way.
Code sample
while (keep_running) {
do_your_work();
down_interruptible(&mysemaphore); // Intention: break out of this
}
Situation 2.
A thread that periodically logs things. This thread sleeps some seconds between doing it's work. After setting the flag this thread terminates at it's next run but this can take several seconds. I want to break the sleep if necessary.
Code sample
while (keep_running) {
do_your_work();
msleep(15000); // Intention: break out of this - msleep_interruptible?
}

How to pause and resume thread?

I am trying to write the program, which will stop and continue thread instead of cancel it. I need to know, how can I achieve that?
I want to use pthread_kill() function with SIGSTOP and SIGCONT signals to thread.
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <time.h>
void *threadfunc(){
while(1){
printf("i am thread \n");
sleep(1);
}
}
void main(){
pthread_t thread;
pthread_create(&thread, NULL, threadfunc, NULL);
sleep(2);
pthread_kill(thread, SIGSTOP);
printf("signal sent \n");
sleep(2);
printf("i am main thread \n");
}
My expectation:
Program starts, 2 times "i am thread" printed, pthread_kill sent signal to stop the thread, user see "signal sent" and "i am main thread".
Actual results:
Programs starts, 2 times "i am thread" printed, pthread_kill sent stop signal and program terminate
There is no one right way to pause and resume a thread.
First, there is no way at all to do it without the cooperation of the code that thread is running. Otherwise, disaster could occur if you pause a thread while it holds a lock that the thread that would resume it needs to acquire before it can resume. So you must have the cooperation of the code the thread you want to pause is running.
With the thread's cooperation, you can do it however you like. You can have an atomic bool that the thread periodically checks. You can just not give the thread work to do if it's designed to pause when it has no work to do.
There's no one right way and it entirely depends on other design decisions. Primarily, it depends on what that code is doing and why you want to pause it.
One other thing that is extremely important: Any time you feel you need to reach into a thread from outside and make it do or not do something, that should be a sign to you that you coded the thread wrong in the first place. A thread should know what work it needs to do and when it needs to not do work by its own design. If something else has to "reach in" intrusively and make it do or not do things, you should re-examine the design decisions that got you to that point.
And to your specific point:
I want to use pthread_kill() function with SIGSTOP and SIGCONT signals to thread.
That couldn't possibly work. What if the thread happens to hold an internal library lock that needs to be acquired to return from pthread_kill? The thread trying to pause it would also pause itself. In any event, SIGSTOP is defined as stopping a process, not a thread.
You cannot use SIGSTOP/SIGCONT signals on threads as they have several major problems:
They are actualy handled by process, not by thread. Even when sent to
thread.
They don't get queued. If you send them faster than handler can receive them, only the first one gets handled. So you can pause thread, loose unpause signal and remain deadlocked because of it.
Luckily there are "realtime signals", which can be used to emulate STOP/CONT behaviour you are looking for. See my proposal here: https://stackoverflow.com/a/68119116/10277365

Interrupt a function inside a main loop after a certain amount of time

I have a main loop, and I have a function that displays a menu with some choices and waits for user's input.
The point is that I also have to check if a new event occures --in my specific case, a new message is received, but this isn't relevant at all-- and I can't wait the user to make an action: I have to implement a timeout for that function.
Here is a simple example of what I'm talking about:
int choice;
for(;;){
/* a new message could be arrived and we should read it now ... */
choice = menu_function();
/*
...but the user still hasn't made an action,
so the menu_function() hasn't returned yet.
*/
switch(choice){
case 1:
break;
case 2:
break;
default:
break;
}
}
So far I thought of using fork() before the menu_function() and kill() this process after it received a SIGALRM signal through alarm(), but I don't think this is the proper solution since it's inside a loop.
What kind of solution should I adopt?
P.S. I don't think this is a duplicate since, as I already said, the function interrupting request is inside a loop. Or at least for me, I think it's a different thing.
Since you mention fork I assume you're on a POSIX system (like Linux or macOS)?
That means you can install a signal handler for SIGALRM in the process doing the waiting, and the reception of the signal should interrupt the blocking operation (with errno == EINTR) which you can check for and have the menu_function return a value meaning "exit". The code in your loop could then check for this value and break out of the loop.
Another alternative is to not use the standard C input functions unless there's actually something to read. You can do this by using the select call with the desired timeout, and poll FILENO_STDIN. If the select function returns with a timeout, again let menu_function return a special value meaning "exit", else it will use the standard C function to read and parse the input.
No need to fork new processes for either the input-handler or the timer.

Trouble using system calls

I have to figure out how to write a programming that loops but cannot be exited using CTRL-C for 5 seconds, but after 5 seconds I can use CTRL-C to end the program. I have been reading up on system calls and what not, but I can't figure out where to start. Here are the exact instructions, if someone could point me in the right direction. Thank you.
Write a C program that uses system calls that creates a loop and cannot be killed with control C for five seconds. When it starts out it prints “I’ve started looping and can’t be killed with ^C. . .” Then every second it prints a message that says “Still looping . . .” After five seconds allow the loop to be killed with control C and display the message “I'm still looping but I can be killed with ^C ...” this is displayed every second until the user kills it.
You want to look at the signal(2) interface. When certain process-related events occur in a UNIX/Linux environment, the operating system will send a signal (essentially a software interrupt) to the process. You can "catch" a signal using the signal function to set a callback function that gets notified when the given signal occurs. For a Ctrl-C you want to look at SIGINT, but there are other signals you can handle with the same interface. As for pausing, that's easy - just use sleep() in a loop.
You can use this one.
void handler(int signo)
{
signal(SIGINT,SIG_DFL);
}
main()
{
signal(SIGINT,SIG_IGN);
signal(SIGALRM,handler);
// your code.
alarm(5);// for 5 seconds.
while(1)
{ sleep(1);
printf("your message\n");
}
}
First ignoring the SIGINT using the singal. And handler for sigalrm. so first 5 seconds ctrl+c will not work. When the sigalrm is found after the ctrl+c will work. So as per your question for particular time period ctrl+c will be stopped.

Resources