I am testing pthread_cancel() functionality with my test code in C. This is not the exact code I am using but a simplified form for explanation.
int main(argc, char *argvp[])
{
while(1) {
start_thread();
sleep(5);
end_thread();
}
}
void my_thread(void *arg)
{
printf("in my thread\n");
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
return 0;
}
void start_thread()
{
pthread_create(&my_id, NULL, &my_thread, NULL);
}
void end_thread()
{
pthread_cancel(my_id);
}
If I do ps aux on my machine, I see that for my above process the RSS section is always increasing.But if I replace pthread_cancel() with pthread_join(), RSS for my process doesn't increase.
I am not allocating any resource in my thread so it seems like pthread_cancel() is not cleaning up some pthread related stuff behind the scenes?
I know pthread_cancel() is killing the thread because my thread count stays stable at 2 (checked with top ... main process + my_thread).
I looked over the pthread_cleanup_pop/push funcs but they look like they are used to clean user allocated memory.
Do I need to use them every time with pthread_cancel()?
Edit: RSS increases in the amount of 4kBytes every once loop.
Calling pthread_detach() after pthread_cancel() will free the resources which were held/used by pthread "itself.
Of-course the user must make sure on his own that his/her own allocated resources inside the now cancelled thread are also free'ed up.
I'm creating a thread for my game. But I found, that if close button is pressed, or the task is killed I cannot properly finish the work, deallocating all the resources I needed inside the program.
I found that Close handler exists, but the example given is an unknown magic to me, because I need to create something similar in ANSI-C.
static BOOL CloseHandler(DWORD evt)
{
if (evt == CTRL_CLOSE_EVENT)
{
m_bAtomActive = false;
// Wait for thread to be exited
std::unique_lock<std::mutex> ul(m_muxGame);
m_cvGameFinished.wait(ul);
}
return true;
}
I know that Winapi has Mutex and conditional variables, but I do not know anything about std::atomic equivalent.
I have this thread start function and inside thread function GameThread I have a regular bool variable m_bAtomActive checked now.
void Start(void* _self)
{
DWORD dwThreadID;
HANDLE hThread;
struct c_class* this = _self;
this->m_bAtomActive = true;
hThread = CreateThread(
NULL,
0,
&GameThread,
_self,
0,
&dwThreadID);
WaitForSingleObject(hThread, INFINITE);
}
I'm bad at threading, what should I do to properly finish the work of my game?
All the additional details will be provided in the comments or on the chat.
UPD: The first thing seems to be easy, it is solvable with this line inside close handler
if(Active)
InterlockedDecrement(&Active);
But the second and third is still under question. They might be created for the reason of CloseHandler killing the app before destruction, but I don't know for sure.
I'm writing a C program.
For thread I use the WINAPI library.
But sometimes the CreateThread function don't launch the function associate.
I used the WaitForSingleObject function with INFINITE param to let my thread start but he never start
The GetLastError functions return always 0,so I don't know where is my mistake
The merge function is call when GTK button is press.
Below you will find my code
void merge(GtkWidget *wiget, gpointer data){
HANDLE thread;
FtpLogin *login = (FtpLogin *) data;
thread = CreateThread(NULL, 0, mergeThread, login, 0, NULL);
printf("%ld", GetLastError());
WaitForSingleObject(thread, INFINITE);
if(thread == NULL)
puts("error");
}
DWORD WINAPI mergeThread( LPVOID lpParam )
{
puts("Thread start");
return 0;
}
Thanks for your help
The C run-time library needs some per-thread initialization. CreateThread(), which knows nothing about the C RTL, doesn't perform that.
Instead of CreateThread(), use _beginthreadex(). It's declared in <process.h>.
According to this page, GTK is not thread safe. Anything that interacts with the GUI inside your mergeThread function can have unexpected results.
Please refer to the link I provided for more information about multithreaded GTK applications to see how to use GDK instead.
My objective is to create a thread that is reusable and not one that terminates when reaching the end of the thread function.
This is a pseudo code of what I'm trying to achieve with pthreads:
bool doRun = true;
void thread_func( void* p ) {
while( doRun ) {
waitForSignal() // just like waitForSingleObject
// run thread
}
}
I used the win32 function waitForSingleObject together with an Event in the past quite a lot and I have no idea how to implement that kind of behavior with pthreads.
Your help is appreciated
Using GTK and C, how can I start/stop a long calculation (in a seperate thread) using a button? I have working code that does just that but I have little confidence that it isa reasonable method (i.e., "right").
I have a single button whose label toggles from "start" to "stop". I also have a global pthread_t variable to store a thread. My approach is to either launch or cancel a thread through the button's clicked signal handler depending on the value of a global boolean-like "idle" flag which indicates if the thread is currently running or not.
I wanted a working well-designed minimum test case so that I can easily understand the code to adapt for a larger program. This question is very similar to Python&PyGTK: Stop while on button click but that question is in python which I don't know.
My code --- posted below --- seems to work but I'm not confident in it because I can easily bring the system to its knees by just clicking the start/stop button a few times in rapid succession.
I'd be curious to see how others would (independently) solve this, how their approach compares to mine, and also a code-review for my own approach if it is actually a decent way.
#include <gtk/gtk.h>
#include <pthread.h>
/* suppress unused variable warnings */
#define UNUSED(x) (void)(x)
typedef struct _Data {
GtkWidget *window1,
*button1;
gint idle;
pthread_t calcthread;
} Data;
static Data *data;
void *calcfunc(void *arg) {
int i;
UNUSED(arg);
data->idle=FALSE;
gtk_button_set_label(GTK_BUTTON(data->button1),"Stop");
/* This is intended to simulated a long calculation that may finish.
Adjust the limit as needed */
for(i=1;i<2e9;++i) {
}
data->idle=TRUE;
pthread_exit(NULL);
}
/* this is our click event handler.... it suppose to start or stop
the "calcthread" depending on the value of the "idle" flag */
void on_button1_clicked(GtkWidget *widget, Data *ldata) {
int ret;
UNUSED(widget);
UNUSED(ldata);
if ( data->idle==TRUE ) {
printf("idle.. starting thread\n");
ret=pthread_create( &data->calcthread, NULL, calcfunc, NULL);
if ( ret !=0 ) {
g_error("ERROR: could not create thread\n");
}
} else {
printf("not idle... canceling thread...");
ret= pthread_cancel( data->calcthread );
if ( ret != 0 ) {
g_error("ERROR: could not cancel thread\n");
} else {
printf("canceled\n");
}
data->idle=TRUE;
gtk_button_set_label(GTK_BUTTON(data->button1),"start");
}
}
/* just defines our setup */
int main (int argc, char *argv[]) {
g_thread_init(NULL);
gdk_threads_init();
gdk_threads_enter();
gtk_init(&argc, &argv);
data=g_slice_new0(Data);
data->idle=TRUE; /* initial state */
printf("idle is %d\n",data->idle);
/* add widgets and objects to our structure */
data->window1=gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(data->window1),250,250);
data->button1=gtk_button_new_with_label("Start");
gtk_container_add(GTK_CONTAINER(data->window1),GTK_WIDGET(data->button1));
gtk_signal_connect(GTK_OBJECT(data->window1), "delete-event",
gtk_main_quit, NULL);
gtk_signal_connect(GTK_OBJECT(data->button1), "clicked",
G_CALLBACK(on_button1_clicked), NULL);
gtk_widget_show_all(GTK_WIDGET(data->window1));
gtk_main();
/* Don't forget to free the memory! */
g_slice_free(Data, data);
gdk_threads_leave();
return 0;
}
As you are calling GTK functions from the secondary thread you need to wrap the call to
gtk_button_set_label(GTK_BUTTON(data->button1),"Stop");
with gdk_threads_enter/gdk_threads_leave calls. However, it is better practice to only call GTK functions from one thread. The easiest way is with an idle function using g_idle_add as this will be called from the main thread, however in your case you could just move the call to gtk_button_set_label from calcfunc into on_button1_clicked.
You should also set data->idle = FALSE in the on_button1_clicked handler to solve the race condition where you click the button too quickly.
Another way you could do this is without threads and that is to run the GTK main loop during the long operation. In your loop you just need to pump the Gtk event loop.
for(i=1;i<2e9;++i) {
while (gtk_events_pending ()) {
gtk_main_iteration ();
}
}
This means you avoid all the threading problems and needing to lock data access. You could stop the calculation by checking a boolean value each iteration which gets set in the on_button1_clicked handler.
The following code does what I asked. It uses pthreads. I don't know if it's the most elegant but it seems to work. The trick was using two flags: one for the idle state and one for a cancel request, which avoids needing to cancel the thread using the "pthread_cancel" function, which I find to be unusual in real code.
#include <gtk/gtk.h>
#include <pthread.h>
#include <errno.h>
#include <stdlib.h>
#define UNUSED(x) (void)(x)
#define handle_error_en(en, msg) do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
typedef struct _Data {
GtkWidget *window1,
*button1;
} Data;
static Data *data;
static pthread_mutex_t calcmutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_t calcthread=0;
static gboolean idle=TRUE,cancel_request=FALSE;
void *calcfunc(void *arg) {
int i,s;
UNUSED(arg);
g_print("\tstarting thread\n");
s = pthread_setcancelstate(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
if (s != 0) {
handle_error_en(s, "pthread_setcancelstate");
}
gdk_threads_enter();
gtk_button_set_label(GTK_BUTTON(data->button1),"Stop");
gdk_threads_leave();
g_print("\tstarting work...\n");
for (i=0; i<100000000 ;++i) {
/* check for cancelation */
pthread_mutex_lock(&calcmutex);
if ( cancel_request ) {
g_print("\t[cancel request noted].\n");
pthread_mutex_unlock(&calcmutex);
break;
}
pthread_mutex_unlock(&calcmutex);
/* do "calculation" */
i=i*1*-1*1*-1;
}
g_print("\tdone work.\n");
gdk_threads_enter();
gtk_button_set_label(GTK_BUTTON(data->button1),"Start");
gdk_threads_leave();
pthread_mutex_lock(&calcmutex);
cancel_request=FALSE;
idle=TRUE;
pthread_mutex_unlock(&calcmutex);
g_print("\tdone thread.\n");
pthread_exit(NULL);
}
void on_button1_clicked(GtkWidget *widget, gpointer *ldata) {
int s;
UNUSED(widget);
UNUSED(ldata);
g_print("entered on_button1_clicked\n");
pthread_mutex_lock(&calcmutex);
if ( idle ) {
g_print("idle, starting thread\n");
s = pthread_create(&calcthread, NULL, calcfunc, NULL);
if (s != 0) {
handle_error_en(s, "pthread_create");
}
idle=FALSE;
} else {
g_print("not idle and not first time, making canceling request.\n");
cancel_request=TRUE;
}
pthread_mutex_unlock(&calcmutex);
g_print("finished on_button1_clicked\n");
}
/* just defines our setup */
int main (int argc, char *argv[]) {
g_thread_init(NULL);
gdk_threads_init();
gdk_threads_enter();
gtk_init(&argc, &argv);
data=g_slice_new0(Data);
printf("initial idle is %d\n",idle);
/* add widgets and objects to our structure */
data->window1=gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(data->window1),250,250);
data->button1=gtk_button_new_with_label("Start");
gtk_container_add(GTK_CONTAINER(data->window1),GTK_WIDGET(data->button1));
gtk_signal_connect(GTK_OBJECT(data->window1), "delete-event",
gtk_main_quit, NULL);
gtk_signal_connect(GTK_OBJECT(data->button1), "clicked",
G_CALLBACK(on_button1_clicked), NULL);
gtk_widget_show_all(GTK_WIDGET(data->window1));
gtk_main();
/* free the memory and stuff */
g_slice_free(Data, data);
pthread_mutex_destroy(&calcmutex);
gdk_threads_leave();
return 0;
}
This compiles warningless with
gcc -Wall -Wextra -Wconversion -pedantic `pkg-config --cflags --libs gtk+-2.0` start_stop.c -o start_stop
Well in Java I would call interrupt() on that Thread, the thread would then get an InterruptedException, and would be able to clean up in its exception handler's catch or finally block before exiting.
In C there is several options:
send that thread a signal with kill(), and have the signal handler longjmp() to a point in your code where you previously called setjmp(). For cleanup, you'd just do something when setjmp() returns non-zero, meaning it's resuming from the subsequent longjmp() call.
call pthread_cancel(). The only real cleanup you get here is that the cancellation handlers you previously registered with pthread_cleanup_push() will get called.
have either a volatile variable or a lock protected variable that gets checked periodically (for example once every loop iteration) and set to some value when the calculation should be canceled. Cleanup is easy because you can do whatever you like when the flag is set and you break out of the loop.
I dislike all of them: signals mean you have to handle partial failures (eg. short reads and writes on files and sockets) and errno==EINTR correctly everywhere in your code while avoiding all kinds of gotchas that exist with signal handlers (such as the small stack size and limits on what system calls are safe to use), pthread_cancel() means you have to drag state around between the thread function and the cancellation handlers, and the flag can impact performance since it has to read uncached memory or take a lock every time and if you don't check it often enough then the thread won't respond immediately when the flag is set.