Im doing a game in C using Threads for windows, but in a point of the game i need to stop some threads in a specific moment, I dont know either the function and the parameters that i need to stop a thread neither what it returns.
This 2 Function are the same, a simple timer that run until the counter reach limit, i want to stop the second thread whenever i want, without using the second parameter of WaitForSingleObject(hThread, Miliseconds).
DWORD WINAPI timer(LPVOID segundo)
{
int counter = 0;
while(counter<segundo)
{
counter++;
gotoxy(30,5);
printf("%d", counter);
Sleep(1000);
}
return NULL;
}
DWORD WINAPI prueba(LPVOID segundo)
{
int counter = 0;
while(counter<segundo)
{
counter++;
gotoxy(30,10);
printf("%d", counter);
Sleep(1000);
}
return NULL;
}
int main()
{
int limit = 5, *ptr;
*ptr = limit;
HANDLE hThread1, hThread2;
DWORD time, probo;
hThread1 = CreateThread(NULL, 0, timer, *ptr, 0, &time);
hThread2 = CreateThread(NULL, 0, prueba, *ptr, 0, &probo);
WaitForSingleObject(hThread2, INFINITE);
WaitForSingleObject(hThread1,INFINITE);
return 0;
}
Create an event using CreateEvent(NULL,FALSE,FALSE,NULL) function, pass this event handle into thread, then in the thread procedure, use WaitForSingleObject(hEvent,1000) instead. Whenever you want to stop the thread, call SetEvent(hEvent), then in the thread proc, do:
DWORD retval = WaitForSingleObject(hEvent,1000);
if( retval != WAIT_TIMEOUT )
return 0;
In C, one usually use a global BOOL, bTerminated, which is initially set to FALSE. The thread repeatedly checks its value, e.g. in your thread function while(counter<segundo && !bTerminated) would be written. Any other part of the code, which wants to stop the thread, should set bTerminated to TRUE, and wait for the thread to stop is needed, by calling WaitForSingleObject. If you have more than one thread, you can use such a logical variable for each thread.
This solution is also the standard approach in Delphi, but in this case the bTerminated variable is a field of the TThread class, and is set to true bay calling the Terminate method. There are similar implementations in C++, too.
Related
I want to simulate Java's behavior of waiting until all threads in the process finish before the main exits in C/Windows API.
The behavior I want to simulate is one of the sample code below(it spams [second thread] active threads: 2., and does not terminate even when main returns):
public final class Test1
{
// | prints current thread count and queues the next iteration.
static void step() {
System.out.println (
"[second thread] active threads: " +
Thread.activeCount() +
"."
);
new Thread(() -> step()).start();
}
public static void main(String[] args) throws Exception
{
// | queue the first iteration.
new Thread(() -> step()).start();
}
}
My initial idea was to completely take over the main of my program, and instead do all the work in another function, eg main2 and if it finishes early, I will wait until the rest of the threads finish.
My problem is that my main has no idea what other threads exist, and even if it did know what other threads existed, after they all finish, it is still possible that they have spawned more threads, that we are again not aware of.
My approach to tackle this looks something as follows:
main.c would contain the actual main, and the actual main logic would be moved out to main2(or something with a better name). main would potentially resort to using CreateToolhelp32Snapshot to discover threads that do not match its own GetThreadId and wait for them(potentially aggregating existing threads to avoid only fetching one existing thread at a time, to take advantage of WaitForMultipleObjects).
/**
* #file main.c
*/
#include <Windows.h>
// | This function will can start threads without worrying about them
// | ending as soon as it finishes.
extern int main2(int argc, char **argv);
// | NOT IMPLEMENTED: I have no idea if such a service exists, but it can probably be
// | implemented using CreateToolhelp32Snapshot.
// | If it did exist, it would return a single thread from the process
// | not matching the current thread id.
extern HANDLE WINAPI SorceryToDiscoverASingleOtherThreadThatExists();
int main(int argc, char **argv)
{
int returnValue;
// | main2 will do the actual main's work.
returnValue = main2(argc, argv);
// | Do not finish before other threads finish.
for (;;) {
HANDLE hThread;
// | Find a single thread handle whose thread id is
// | not the same as the current thread's.
hThread = SorceryToDiscoverASingleOtherThreadThatExists();
// | If there are no more threads,
// | we can finally break out of this infinite loop.
if (hThread == 0) {
break;
}
WaitForSingleObject(hThread, INFINITE);
}
return 0;
}
And main2.c which would behave as our java program would:
/**
* #file main2.c
*/
#include <Windows.h>
#include <stdio.h>
DWORD CALLBACK ThreadProc0001(LPVOID unused) {
puts("Hello, World!");
CreateThread(0, 0, ThreadProc0001, 0, 0, 0);
return 0;
}
int main2(int argc, char **argv)
{
CreateThread(0, 0, ThreadProc0001, 0, 0, 0);
return 0;
}
With proof of concept to make sure the above code works(deep_thread_nesting.c):
/**
* #file deep_thread_nesting.c
*/
#include <Windows.h>
#include <stdio.h>
DWORD CALLBACK ThreadProc0001(LPVOID unused) {
puts("Hello, World!");
CreateThread(0, 0, ThreadProc0001, 0, 0, 0);
return 0;
}
int main(int argc, char **argv)
{
CreateThread(0, 0, ThreadProc0001, 0, 0, 0);
// | Do not exit until user presses ctrl c.
for (;;) {
// | Reduce strain on the CPU from the infinite loop.
Sleep(1000);
}
return 0;
}
My problem is that I feel forced to use one of three incredibly ugly solutions:
The first involving the mystical CreateToolhelp32Snapshot function as this tutorial describes, in order to fetch one(or potentially be optimized further to return more than one thread that does not match our active thread id) thread handle(s) that we can use to wait on.
The second involving keeping a global registry of all the handles and having each thread lock the world, add the handle to the registry, remove its own handle, and unlock the world, possibly writing my own CreateThread wrapper that takes care of this for me.
The third being a rough idea, as I have no idea if this even works the way I think it does, hooking the CreateThread function to make all threads implement the second solution.
Question
Is there a way to make C or Windows API wait for all my threads to finish
before terminating the program without effectively writing my own runtime?
Not really an answer, but, as mentioned by IInspectable, ExitProcess is called by the CRT. So getting rid of the CRT the behaviour that you are looking for is restored.
Compile with /NODEFAULTLIB, include libraries using the command line and not #pragma comment(lib, ...).
#include <Windows.h>
DWORD WINAPI other_thread(LPVOID lpThreadParameter)
{
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
if ((hOut == INVALID_HANDLE_VALUE) ||
(!hOut))
{
if (IsDebuggerPresent()) __debugbreak();
return -1;
}
constexpr char string[] = "I am writing!\r\n";
for (;;)
{
WriteFile(hOut, string, sizeof(string), 0, 0);
}
return 0;
}
int mainCRTStartup()
{
HANDLE hThread = CreateThread(0, 0, other_thread, 0, 0, 0);
return 1;
}
The other_thread continues writing, even after the mainCRTStartup exits.
An answer that is closer to what the OP intended:
#include <windows.h>
#pragma comment(lib, "synchronization.lib")
// the program will not (usually) exit, until this counter is at 0
long long deployed_threads_counter;
// we need a place to store the user's function pointer,
// as the lpStartAddress parameter of CreateThread is already used
struct ThreadParameters
{
LPTHREAD_START_ROUTINE lpStartAddress;
LPVOID lpParameter;
};
// a wrapper around the user provided LPTHREAD_START_ROUTINE
DWORD WINAPI my_thread_start(LPVOID lpThreadParameter)
{
// dereferenced! my_create_thread can now exit
ThreadParameters thread_parameters = *(ThreadParameters*)lpThreadParameter;
WakeByAddressSingle(lpThreadParameter);
// actually do the work
BOOL result = thread_parameters.lpStartAddress(thread_parameters.lpParameter);
// signal that the thread has finished executing
InterlockedDecrement64(&deployed_threads_counter);
WakeByAddressSingle(&deployed_threads_counter);
return result;
}
// CreateThread substitude incurs the desired behaviour
HANDLE my_create_thread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId)
{
InterlockedIncrement64(&deployed_threads_counter);
ThreadParameters thread_parameters =
{
lpStartAddress,
lpParameter,
};
// call my_thread_start instead, so that the thread exit is signaled
HANDLE hThread = CreateThread(
lpThreadAttributes,
dwStackSize,
my_thread_start,
&thread_parameters,
dwCreationFlags,
lpThreadId);
// do not destroy thread_parameters, until my_thread_start has finished using them
WaitOnAddress(&thread_parameters, &lpStartAddress, sizeof(LPTHREAD_START_ROUTINE), INFINITE);
return hThread;
}
// optionally set this behaviour to be the default
#define CreateThread my_create_thread
int use_this_main();
int main()
{
// execute user code
int result = use_this_main();
// wait for all threads to finish
while (auto temp = deployed_threads_counter)
{
WaitOnAddress(&deployed_threads_counter, &temp, sizeof(temp), INFINITE);
}
// fallthrough return
return result;
}
int use_this_main()
{
// your code here...
return 0;
}
Currently there is actually a race condition, if InterlockedIncrement64 is called after the main's WaitOnAddress. This can be prevented, with something like a double gate system, but the answer is already complicated enough.
I am trying to do this implementation but it's not working properly.
I have a global variable called counter which starts at 100 and I have two threads.
Both threads are decrementing the counter in a while loop that runs if counter is != 0.
However though the thread which does decrement the counter to 0 will stop running as expected. But the thread which does not decrement the counter continues running when it should stop.
How do I fix this?
Below is my code:
int counter = 0;
pthread_mutex_t counter_mutex;
void *Thread1(void *vargs)
{
while (counter != 0) {
pthread_mutex_lock(&counter_mutex);
counter--;
pthread_mutex_unlock(&counter_mutex);
}
sleep(1);
printf("Completed Thread1\n");
return NULL;
}
void *Thread2(void *vargs)
{
while (counter != 0) {
pthread_mutex_lock(&counter_mutex);
counter--;
pthread_mutex_unlock(&counter_mutex);
}
sleep(1);
printf("Completed Thread2\n");
return NULL;
}
int main(void)
{
pthread_t tid[2];
// initialize the mutex
pthread_mutex_init(&counter_mutex, NULL);
// create worker threads
pthread_create(&tid[0], NULL, Thread1, NULL);
pthread_create(&tid[1], NULL, Thread2, NULL);
// wait for worker threads to terminate
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
// print final counter value
printf("Counter is %d\n", counter);
return 0;
}
Output:
Completed Thread1
Thread1 completes but the program runs indefinitely because Thread2 stays in the while loop and doesn't finish.
Or vice versa, where Thread2 completes and then runs indefinitely because Thread1 stays
in the while loop and doesn't finish.
I'm really confused on how to approach fixing this problem because the two Threads should be running and stopping when counter == 0. However only the Thread that decrements counter to 0, stops while the other runs indefinitely.
Any and all help is really appreciated!
Thank you so much
At some point, while one thread will be blocked waiting to lock the mutex, the other will have decremented counter to zero. As soon as the waiting thread gains access to the lock, it will decrement as well, resulting in -1. counter will never approach zero again, and it will be decremented until Undefined Behavior is invoked by overflowing a signed integer.
None of this really matters, because the read of counter in each while loop predicate is not protected by the mutex
while (counter != 0)
which means you can have a read/write race condition.
Instead, structure your locks so they fully surround all reads & writes, and adjust your predicate to be independently checked.
#include <pthread.h>
#include <stdio.h>
int counter = 0;
pthread_mutex_t counter_mutex;
void *runner(void *arg) {
int *n = arg;
int done = 0;
while (!done) {
pthread_mutex_lock(&counter_mutex);
if (counter == 0)
done = 1;
else
counter--;
pthread_mutex_unlock(&counter_mutex);
}
printf("Completed Thread %d\n", *n);
return NULL;
}
int main(void)
{
pthread_t tid[2];
int args[2] = { 1, 2 };
pthread_mutex_init(&counter_mutex, NULL);
pthread_create(&tid[0], NULL, runner, &args[0]);
pthread_create(&tid[1], NULL, runner, &args[1]);
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
printf("Counter is %d\n", counter);
return 0;
}
FYI: This is practically always a bad idea:
while (...trivial condition...) {
pthread_mutex_lock(&some_mutex);
...do some work...
pthread_mutex_unlock(&some_mutex);
}
The reason it's bad is that the loop tries to keep the mutex locked almost 100% of the time. The only time when the mutex is not locked is the brief moment when the loop evaluates the "...trivial condition..."
There's no point in executing the loop in more than one thread at the same time because the mutex prevents more than one thread from ever doing "...work..." at the same time.
If you're trying to use threads for parallel computing, then something like this works better:
typedef struct { ... } task_t;
int find_a_task(task_t* task) {
int result = FALSE;
pthread_mutex_lock(&some_mutex);
if (...there's more work to be done...) {
...copy from shared data into *task...
result = TRUE;
}
pthread_mutex_unlock(&some_mutex);
return result;
}
task_t local_task;
while (find_a_task(&local_task)) {
do_some_heavy_work_on(&local_task);
pthread_mutex_lock(&some_mutex);
if (...contents of local_task still are meaningful...) {
copy from local_task back to shared data structure
}
pthread_mutex_unlock(&some_mutex);
}
The idea is, to do most of the heavy work without keeping any mutex locked. The mutex is only briefly locked (a) before doing the heavy work, to copy shared data into private, local variables and (b) after the heavy work, to copy results, if still valid,* back into the shared data.
* The result might not still be valid because of some other thread changing shared data items that the caller used. This is optimistic locking. It may sound inefficient, but in many programs, the efficiency gained by not keeping a mutex locked while doing heavy work is MUCH greater than the efficiency lost because of threads occasionally duplicating or invalidating each other's effort.
So I'm creating a drone simulation with Pthreads and Ncurses, I can have my code work perfectly for any number of threads synchronously, simply using a Mutex to serialize the updating of my screen. However I want to create an asynchronous simulation. Right now I'm trying to use the POSIX condvar. The idea is to the synchronize the threads on movement. So say I want to move 10 threads in 10 positions in the x direction. I want Thread1 to move one unit in the X direction, then give Thread2 the ability to move in the x-direction and so on. This is just my code for handling the creation of the pthreads and attempting synchronization:
int init_threads()
{
int rc = 0; int i = 0; long t = 0;
pthread_t threads[NUM_THREADS];
pthread_mutex_init(&mutex_lock, NULL);
pthread_cond_init(&count_threshold_cv, NULL);
for(i; i < 2; i++)
{
rc = pthread_create(&threads[i], NULL, DCAS, (void *)t);
if(rc)
{
printf("Error return from create is %d\n", rc);
return -1;
}
}
pthread_exit(NULL);
}
void * DCAS(void * PID)
{
Tuple win = find_window();
int start_x = win.a/2; int start_y = win.b/2;
pthread_mutex_lock(&mutex_lock);
while(start_x != 10)
{
pthread_cond_wait(&count_threshold_cv, &mutex_lock);
}
update_screen();
pthread_mutex_unlock(&mutex_lock);
}
void update_screen()
{
Tuple win = find_window();
int start_x = win.a/2; int start_y = win.b/2;
pthread_mutex_lock(&mutex_lock);
mvwaddch(local_win, start_x, start_y, 'o');
init_base_layouts();
wrefresh(local_win);
sleep(1);
start_x--;
pthread_cond_signal(&count_threshold_cv);
pthread_mutex_lock(&mutex_lock);
}
It is exactly creating two pthreads and attempting to signal the cond-var when a thread is moved to allow another thread the ability to move in the same x-direction for 10 x positions. I cant seem to get the condition to signal that the thread has moved however. Thanks so much in advanced!
If you wait on a condition variable, you must be waiting for some particular condition over some shared state to change (that's why it's called a condition variable).
However, the condition you are waiting on (while (start_x != 10)) is not over shared state: start_x is a local variable to each thread, which is not shared.
It's not clear exactly what state you want to wait for: however, if what you want is for each thread to move once and then not move again until all the other threads have had a chance to move, then a pthread barrier might be the appropriate primitive.
In the main function, before the threads are created:
pthread_barrier_init(&barrier, NULL, NUM_THREADS);
(where NUM_THREADS is the number of moving threads that are to be created). Then in each moving thread:
for (i = 0; i < 10; i++)
{
move();
pthread_barrier_wait(&barrier);
}
All the threads will then move once (in an unspecified order), and then not continue until all other threads have moved as well.
How can I exit or stop a thread immediately?
How can I make it stop immediately when the user enters an answer?
I want it to reset for every question.
Here's my code where threading is involved
int q1() {
int timer_start;
char ans[] = "lol";
char user_ans[50];
timer_start = pthread_create( &xtimer,NULL,(void*)timer_func,(void*)NULL);
printf("What is the capital city of Peru?\n");
while(limit){
scanf("%s",user_ans);
if(limit)
{
if(!strcmp(user_ans, ans))
{
// printf("YAY!\n");
score++;
// q2();
}
else
{
game_over();
}
}
}
}
You can simply call pthread_cancel on that thread to exit it. And you can send SIGSTOP/SIGCONT signal via pthread_kill to stop/restart it.
But if all you want is a timer, why must you thread?
Based on your code I can give a simple answer:
In this case do not use threads at all.
You do not need them. Store the start time, let the user answer, check the time again after user gives an answer.
{
time_t startTimeSec = time(NULL);
// answering
time_t endTimeSec = time(NULL);
time_t timeTakenSec = endTime-startTime;
if (timeTaken > 10) {
// do your thing
}
}
To answer your question:
You should use a mutex-protected or volatile variable to asynchronously communicate between threads. Set that variable from one thread and check it in another. Then reset its value and repeat. A simple snippet:
int stopIssued = 0;
pthread_mutex_t stopMutex;
int getStopIssued(void) {
int ret = 0;
pthread_mutex_lock(&stopMutex);
ret = stopIssued;
pthread_mutex_unlock(&stopMutex);
return ret;
}
void setStopIssued(int val) {
pthread_mutex_lock(&stopMutex);
stopIssued = val;
pthread_mutex_unlock(&stopMutex);
}
Using pthread_cancel() is an option, but I would not suggest doing it. You will have to check the threads state after this call returns, since pthread_cancel() does not wait for the actual thread stop. And, which to me is even more important, I consider using it ugly.
Using methods to stop a thread is a brute way.
You should rather politely ask the thread to stop by signalling.
Thereby the thread will have an option to tidy after itself e.g. if it has allocated memory, which it will not have any opportunity to do if the thread is cancelled.
The method is relatively simple and comprises no OS signalling:
define a thread state variable or structure outside the thread. Point to it at the pthread_create and dereference the state variable in the thread.
int thread_state = 0; // 0: normal, -1: stop thread, 1: do something
static void *thread_1 (void *arg)
{
int* pthread_state = arg;
... // initialize the thread locals
while(1)
{
switch( *pthread_state )
{
case 0: // normal thread loop
...
break;
case -1:
... // tidy or whatever is necessary
pthread_exit(0); // exit the thread signalling normal return
break;
case 1: //
... // do something special
break;
}
}
}
pthread_create (&t_1, NULL, thread_1, (void*)&thread_state);
...
thread_state = -1; // signal to the thread to stop
// maybe use pthread_exit(0) to exit main.
// this will leave the threads running until they have finished tidy etc.
It is even possible to communicate with the thread using a structure provided that it is simple 'atomic' variables or a simple handshake mechanism is established. Otherwise it may be necessary to use mutex.
Use pthread_join to wait for threads to terminate.
#Naruil's suggestion to call pthread_cancel() is pretty much the best solution i found, but it won't work if you didn't do the following things.
According to the man-page of pthread_cancel the pthread_cancelibility depend on two thing
thread_cancel_state.
thread_cancel_type.
thread_cancel_state is PTHREAD_CANCEL_ENABLE by default, so our main concern is about the thread_cancel_type, it's default value is type PTHREAD_CANCEL_DEFFERED but we need PTHREAD_CANCEL_ASYNCHRONOUS to set on that thread, which we wan't to cancel.
Following an example given::
#include <stdio.h>
#include <pthread.h>
void *thread_runner(void* arg)
{
//catch the pthread_object as argument
pthread_t obj = *((pthread_t*)arg);
//ENABLING THE CANCEL FUNCTIONALITY
int prevType;
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &prevType);
int i=0;
for( ; i < 11 ; i++)//1 - > 10
{
if(i == 5)
pthread_cancel(obj);
else
printf("count -- %d", i);
}
printf("done");
}
int main(int argc, char *argv[])
{
pthread_t obj;
pthread_create(&obj, NULL, thread_runner, (void*)&obj);
pthread_join(obj, NULL);
return 0;
}
run it using gcc filename.c -lpthread and output the following::
count -- 0
count -- 1
count -- 2
count -- 3
count -- 4
note that the done is never printed because the thread was canceled when the i became 5 & the running thread was canceled. Special thanks #Naruil for the "pthread_cancel" suggestion.
I have a thread called mainloop
i.e.
int run_mainloop;
void* mainloop(void* param)
{
// local vars
// initialize local vars
while(run_mainloop)
{
// run mainloop
}
return 0;
}
The thread is kicked off from a function called client_open, i.e.
int client_open()
{
run_mainloop = 1;
return pthread_create(&thread, NULL, mainloop, NULL);
}
However, in mainloop if initializing local variables fails I need to inform client_open right away of early exit.
pthread_join is inappropriate as it will block and I can't have client_open block.
If it was to wait a short time before returning that would be ok.
How could I do this in a nice way without using pthread_join which will block.
I want to be able to get the return code.
Using pthread_tryjoin_np would be incorrect: the new thread could be arbitrarily delayed between pthread_create return, and the new thread actually executing initialization code.
If you pthread_tryjoin_np during that delay, the join will fail and you will decide that everything is "a-ok", when in fact it isn't.
What you want is a condition: client_open will await on it, and the mainloop will signal it (upon being done with initialization).
You can use something known as completion variables.
Using which a thread can wait till a newly created thread has finished initialization. The only catch is that the new thread must always signal its initialization completion, even when initialization fails.
Something along the following lines (error handling omitted for clarity):
#include <pthread.h>
// Completion variable definition:
typedef struct {
pthread_mutex_t mtx;
pthread_cond_t cnd;
int completed;
int return_code;
} Completion;
#define COMPLETION_INIT { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 }
int completion_wait(Completion* c) { // add timeout if necessary
pthread_mutex_lock(&c->mtx);
while(!c->completed)
pthread_cond_wait(&c->cnd, &c->mtx);
int return_code = c->return_code;
pthread_mutex_unlock(&c->mtx);
return return_code;
}
void completion_signal(Completion* c, int return_code) {
pthread_mutex_lock(&c->mtx);
c->completed = 1;
c->return_code = return_code;
pthread_cond_signal(&c->cnd);
pthread_mutex_unlock(&c->mtx);
}
// Usage:
void* mainloop(void* vc) {
int init_success = 0;
// initialization
// ...
init_success = 1;
init_end:
Completion* c = (Completion*)vc;
completion_signal(c, init_success); // always signal
if(!init_success)
return NULL;
// start the main loop
return NULL;
}
int client_open()
{
int run_mainloop = 1;
pthread_t thread;
Completion c = COMPLETION_INIT;
pthread_create(&thread, NULL, mainloop, &c);
pthread_detach(thread);
return completion_wait(&c);
}
Ok, I discovered three ways to do this.
1) Initialize and pass variables to mainloop before starting it.
2) Use the Linux specific pthread_tryjoin_np() or pthread_timedjoin_np()
I think the timed join version is more appropriate in this case as it allows time for the thread to be created and for initialisation to be done. The timeout need not be long so it will not block the caller to client_open() for very long.
However, as pointed out by #fge they are non-portable. While that isn't too much of a problem I thought about an alternative way which is this.
EDIT: Not such a good solution, but left in here for reference.
It'd be better to signal to open using a condition variable that initialization was ok.
3) Check if run_mainloop is non-zero, if it is and pthread_create didn't fail and the thread is running. If it's still zero after a time then it didn't start so we call pthread_join to get the exit code.
int run_mainloop = 0;
void* mainloop(void* param)
{
// init vars
// if failure, exit early.
// everything from this point on is good.
run_mainloop = 1;
while (run_mainloop))
{
// do styff
}
return 0;
}
int client_open()
{
void* res;
int rc = pthread_create(&g_thread_id, NULL, mainloop, NULL);
if (rc != 0)
return -1;
usleep(100); // wait a little while, kinda dumb but allows time for init
if (run_mainloop))
return 0;
pthread_join(g_thread_id, &res);
return -1;
}