I am supposed to implement a userlevel threads library in C. To do so, I need to implement yield(), createThread() and destroyThread() functions. I believe I've got the basics right:
To keep track of threads, I'll use a queue of ThreadControlBlock elements (which resemble PCBs in an OS) that look like this:
struct ThreadControlBlock {
int ThreadId,
u_context *context };
We can use the setcontext() family of functions to "save" and "load" the context.
Upon initialization of the program, initialize ThreadQueue with no elements.
Now the part I am not getting: when a thread calls yield(), I get the current context and save it in a ThreadControlBlock and put in the queue. Then get the first element in the queue and load the context in it, and execution proceeds.
The question is, if I do this, say I am a thread calling yield() and the next thread is myself. If I am saving the context and loading it again, upon re-entering wouldn't I be at the exact same spot where I was (before calling yield()?) And this would keep going on forever?
When a thread calls yield(), you have to save the state of a thread that's about to return from a yield() call. Don't save the context from immediately before the yield().
The same issue actually applies if you're switching to another task, too - since that other task saved its context at the same point (where it was about to switch to a second task). Using setcontext() and getcontext(), you need to use a static variable to keep track of whether you're switching in or switching out:
static volatile int switched;
switched = 0;
getcontext(current->context);
if (!switched)
{
switched = 1;
setcontext(next->context);
}
Alternatively, you can just use swapcontext(current->context, next->context);
It's perfectly reasonable in your yield() implementation to check to see if the next thread is the current thread and treat that case as a no-op.
If there are no other threads to run besides the current thread then there is nothing else to do besides just return from yield. I wouldn't bother with calling swapcontext in this case, though -- just detect and return.
I think that what you are actually dealing with is what to do when no threads (including the current one) when yield is called. An easy way to deal with this is to have an idle thread, which is only run when the run queue (ready threads) is empty. This thread will probably just:
{
while (1) {
yield();
pause();
}
}
This allows your program to go to sleep (via pause) until a signal happens. Hopefully the signal will be some event that makes one of the other threads ready to run, so the next call to yield will run the other thread instead of running the idle thread again.
Related
I am writing a simple threading library using context switching for a college project. I am having troubles returning from the thread execution.
Originally I switched to a newly created thread like this:
int done = 0;
getcontext(&parent_context);
if (!done) {
done = 1;
setcontext(&(thread->context));
}
return thread->tid;
Where thread->context.uc_link is &parent_context. It works, but I need to call a scheduler upon thread creation instead of just switching to its context. So I set thread->context.uc_link to NULL instead of &parent_context and replaced the above code with
schedule(thread);
scheduler();
return thread->tid;
Where schedule enqueues the thread and scheduler gets the first thread in the queue and calls dispatcher, which is just a call to setcontext. The thing is, I need the thread to return control to the scheduler. The first thing that occurred me was doing:
static void
scheduler()
{
int dispatched = 0;
ucontext_t ret;
// Get the first thread in the queue, then
thread->context.uc_link = &ret;
getcontext(&ret);
if (!dispatched) {
dispatched = 1;
setcontext(&(thread->context));
}
// Remove the dispatched thread from the queue
}
Which is not working - the thread doesn't return control to the scheduler and the program finishes after the thread terminates its execution. I assume this is because I didn't call makecontext after changing uc_link. However, in order to call makecontext I would have to pass to the scheduler the thread's function pointer and arguments, which is not desirable, as I cannot modify the thread data structure to store that (project rules). The threading "libraries" using context switching I found online do a setcontext call inside the thread's function:
http://www.evanjones.ca/software/threading.html
http://nitish712.blogspot.com.br/2012/10/thread-library-using-context-switching.html
This is not desirable either, as the user should not need to do the context switching himself. How can I make the thread return control to the scheduler? One hack I can think of is using a static variable ucontext_t return_context and using it as all thread's uc_link. So before I call the scheduler I do getcontext(&return_context) and the scheduler becomes:
// Get the first thread in the queue, then
// Remove the thread from the queue
setcontext(&(thread->context));
This seems to work, but this way no two threads can execute at the same time. It is not an issue for this project, but it seems wrong. Another issue is that every function calling the scheduler acts sort of as a dispatcher:
int done = 0;
getcontext(&return_context);
if (!done) {
done = 1;
scheduler();
}
fprintf(stderr, "Thread returned\n");
Is this the way to go?
What the code needs to do depends on the environment where the code is running.
If running under a OS like Linux or MAC or Windows, the user does not really have much control.
If running on a 'barebones' platform, The the choice needs to be made:
pre-emptive context switching or permissive context switching.
In pre-emptive context switching, a interrupt handler triggers the scheduler (which will trigger the dispatcher which will actually cause a 'thread' to resume execution) and the scheduler saves the current context, decides what to run next (which will depend on how long since the thread was run and priority of the available contexts and whither the specific context is 'blocked' as in waiting for some event.
In permissive context switching, the thread calls the scheduler, thereby giving up the CPU to to the scheduler, which will resume which ever thread is not blocked & highest priority & been delayed the longest.
The scheduler, in a time sensitive system, will also check that a thread that needs to be run periodically has completed its' prior execution before re-starting that thread. If the thread has not completed its' prior execution, then a error is asserted, with usually involves logging the error and re-starting the system.
So, just what environment is your code expected to run in?
This really is two questions, but I suppose it's better they be combined.
We're working on a client that uses asynchronous TCP connection. The idea is that the program will block until certain message is received from the server, which will invoke a SIGPOLL handler. We are using a busy waiting loop, basically:
var = 1
while (var) usleep(100);
//...and somewhere else
void sigpoll_handler(int signum){
......
var = 0;
......
}
We would like to use something more reliable instead, like a semaphore. The thing is, when a thread is blocked on a semaphore, will the signal get through still? Especially considering that signals get delivered when it switches back to user level; if the process is off the runqueue, how will it happen?
Side question (just out of curiosity):
Without the "usleep(100)" the program never progresses past the while loop, although I can verify the variable was set in the handler. Why is that? Printing changes its behaviour too.
Cheers!
[too long for a comment]
Accessing var from inside the signal handler invokes undefined behaviour (at least for a POSIX conforming system).
From the related POSIX specification:
[...] if the process is single-threaded and a signal handler is executed [...] the behavior is undefined if the signal handler refers to any object [...] with static storage duration other than by assigning a value to an object declared as volatile sig_atomic_t [...]
So var shall be defined:
volatile sig_atomic_t var;
The busy waiting while-loop, can be replaced by a single call to a blocking pause(), as it will return on reception of the signal.
From the related POSIX specification:
The pause() function shall suspend the calling thread until delivery of a signal whose action is either to execute a signal-catching function or to terminate the process.
Using pause(), btw, will make the use of any global flag like var redundant, to not say needless.
Short answer: yes, the signal will get through fine with a good implementation.
If you're going to be using a semaphore to control the flow of the program, you'll want to have the listening be on one child with the actual data processing be on another. This will then put the concurrency fairness in the hands of the OS which will make sure your signal listening thread gets a chance to check for a signal with some regularity. It shouldn't ever be really "off the runqueue," but cycling through positions on the runqueue instead.
If it helps you to think about it, what you have right now seems to basically be a a very rough implementation of a semaphore on its own -- a shared variable whose value will stop one block of code from executing until another code block clears it. There isn't anything inherently paralyzing about a semaphore on a system level.
I kind of wonder why whatever function you're using to listen for the SIGPOLL isn't doing its own blocking, though. Most of those utilities that I've seen will stop their calling thread until they return a value. Basically they handle the concurrency for you and you can code as if you were dealing with a normal synchronous program.
With regards to the usleep loop: I'd have to look at what the optimizer's doing, but I think there are basically two possibilities. I think it's unlikely, but it could be that the no-body loop is compiling into something that isn't actually checking for a value change and is instead just looping. More likely to me would be that the lack of any body steps is messing up the underlying concurrency handling, and the loop is executing so quickly that nothing else is getting a chance to run -- the queue is being flooded by loop iterations and your signal processsing can't get a word in edgewise. You could try just watching it for a few hours to see if anything changes; theoretically if it's just a concurrency problem then the random factor involved could clear the block on its own with a few billion chances.
i have a threadProc
void* ThreadProc(void* xyz)
{
//do some work..
}
now from the main thread.. i call this thread and do not wish to wait for it to finish
WaitForSingleObject(hThread, 0)
now my flow of program is succh that the case may arrive where
first call to thread is not finished and 2nd time same ThreadProc() is called.
So ...
1. How does OS handles this scenario? Will this kind of program give unexpected results?
2. If this is wrong way of doing it, what is the correct way?
Because ultimately I want one function to be called asynchronously, may be running multiple instances at the same time.
Every thread has a separate stack, so as long as all variables in the thread callback function are local, there are no conflicts. But if you would access variables that are global/static, then they are shared between all threads and all access to them needs to be handled carefully. Use mutex/semaphores/critical sections for such. The same goes for calling library functions which you don't know are thread-safe.
Will this kind of program give unexpected results?
That depends entirely on the body of the thread callback function. You should however wait using WaitForSingleObject(hThread, INFINITE). Right now you wait 0ms, which does nothing.
gcc 4.4.3 c89
I have a event loop that runs in a separate thread.
My design is like this below, just sample code to help explain.
I need to somehow wait for the initialization to complete before I can make a call to the get_device_params.
I did put a usleep for 3 seconds just before the call to the get_device_params, but I don't really want to block.
Many thanks for any suggestions,
void* process_events(void *data)
{
switch(event_type)
{
case EVT_INITIALIZED:
/* Device is now initialized */
break;
}
}
int main(void)
{
/* Create and start thread and process incoming events */
process_events();
/* Initialize device */
initialize_device();
/* Get device parameters */
/* However, I cannot run this code until initialization is complete */
get_device_params();
return 0;
}
If this separate thread is a POSIX thread (i.e. you're on a typical UNIX platform), then you can use pthread conditional variables.
You call pthread_cond_wait() in the waiting thread. When the init thread finishes its work, you call pthread_cond_signal(). In my opinion that's a canonical way to wait for initialization in another thread.
I need to somehow wait for the initialization to complete before I can make a call to the get_device_params.
Since you apparently have some sort of a FSM inside the process_events(), and it why ever runs in a separate thread, you shouldn't do anything from the main thread with the device.
In other words, logically, call to the get_device_params(); should be placed inside the FSM, on the event that the device is initialized EVT_INITIALIZED which I presume is triggered by the initialize_device().
Alternatively, you can create second FSM (possibly in another thread) and let the process_events() (the first FSM) after it has finished its own processing, forward the EVT_INITIALIZED event to the second FSM. (Or initialize_device() could send the event to the both FSMs simultaneously.)
To me it seems (from the scarce code you have posted) that your problem is that you try to mix sequential code with an event based one. Rule of thumb: in event/FSM based application all code should run inside the FSM, being triggered by an event; there should be no code which may run on its own outside of the FSM.
If it were me, I would probably use a barrier. In main you can call pthread_barrier_init, indicating that you have 2 threads. Then, in main call pthread_barrier_wait, to wait on the barrier you initialized, after calling your device initialization function. Finally, in the device thread, after you initialize your device, you can call pthread_barrier_wait on the same barrier and when both threads are waiting, the barrier will have been satisfied, so both threads will continue. I find barriers easier to use than condition variables sometime, but I'm sure that's an issue of preference.
OK, I'm a bit confused here. The following code works:
HANDLE CreateSideThread()
{
DWORD dwGenericThread;
HANDLE hThread1 = CreateThread(NULL, 0, CallBackFunc, NULL, 0, &dwGenericThread);
return hThread1;
}
int main()
{
HANDLE Thread1;
Thread1 = CreateSideThread();
WaitForSingleObject(hThread1, INFINITE);
SomeOtherFunction();
return 0;
}
The program does other things but you get the idea. It basically creates a new thread and executes whatever it is in CallBackFunc (which is an endless loop that check db status).
Now, if I remove WaitForSingleObject() then the program will not even try CallBackFunc once and execute SomeOtherFunction().
What's the point then of a thread? I mean, i'm confused here.
What I am trying to do is call that thread with the check for the database status and keep that thread going while I continue with my program, calling other functions.
What am I doing wrong?
Please post a sample snippet.
Thanks
Without the WaitForSingleObject, your call to SomeOtherFunction() probably returns quickly enough for the program to exit before the new thread even gets a chance to run once.
When a C program returns from its main() function, the runtime system calls exit() for you. This forcibly exits your program even if other threads are trying to run at the same time. This is in contrast to other languages like Java for example, where exiting the main thread will not exit the process until all other (non-daemon) threads have finished running too.
Threads are typically used for doing background work and freeing up the calling thread to do other things.
Normally, the behavior you describe (calling SomeOtherFunction()) is exactly what you'd want: I am going to kick of a background 'job' and go about my life.
It would appear that your example is just fine - though if you merely return from main() your thread will of course terminate (as it's owned by the parent process).
Maybe some more detail on why what you're doing isn't what you expect to happen?
What you're finding is that the main thread completes before you notice CallbackFunc is called. When you have the Wait call in, the main thread is blocked until the new thread finishes and so you see the thread func being executed.
Threads are not as cheap as you think, if you replace the SomeOtherFunction with something that takes a long enough time to run, you'll see your thread function being called even without the Wait call.
CallBackFunc will of course be called, but there is no guarantee, when your stared threads will be up and running. They will be working once, but its unpredictable when the start doing so. Thats the job and property of the systems scheduler. In your case they do not anything when the second function is already called.