Cooperative Threading, No assignment - multithreading

To preface I love rolling my own, this is an exercise for learning purposes, but I want to take the information from this exercise eventually and implement some macros encapsulating the behaviors here. Thats why im using alot of let because nothing is finalized yet and defines are too "heavy".
So you can use call/cc to implement all kinds of different cooperative threading constructs, and the model for a thread that im using is generally:
(let ((generic-thread
(lambda (cc)
(let loop ((cc cc))
(printf "doing stuff~N")
(loop (call/cc cc)))))) ;this is the magic, it calls the calling continuation
(let loop ((its 0) ;and then loops with the result of that
(cc generic-thread)) ;so when its resumed, it still has its new state
(if (< its 10)
(loop (+ its 1) (call/cc cc))))) ;just repeats the procedure for the demonstration
And so far this works really well actually.
So in my problem, I feel ive identified a few base cases, threads with an exit clause, those without them, and threads that cannot be resumed, or one shots (essentially just a function call, but I want to be consistent so it has to be in a "thread" and not just a function call)
(let ((spawn-thread
(lambda (it . args)
(call/cc (apply it args))))
(main
(lambda (label reps . sequence)
;for consistency, main is also a thread, but does not need to be
;this will take a number of repetitions, and a sequence of continuations
;to call, pushing the continuation returned from the top continuation in
;sequence to the end, and then calling the loop again
(lambda (cc)
(let loop ((sequence sequence) (state 0))
(printf "IN MAIN THREAD STATE: ~A~N---" state)
(if (< state reps) ;this is essentially a queue but without assignment
(loop `(,#(cdr sequence) ,(call/cc (car sequence)))
(+ state 1)))))))
(with-exit
(lambda (label data)
;thread with exit case
(lambda (cc)
(let loop ((cc cc) (done (lambda () #f)) (state 0))
(cond ((done) (cc data)) ;if done was replaced with something else that
;could at some point return true, this is where
;the thread would exit
(else
(printf "IN THREAD ~A TYPE: WITH-EXIT STATE: ~A~N" label state)
(loop (call/cc cc) done (+ state 1))))))))
(no-exit
(lambda (label data)
;no exit case, can be resumed arbitrarily
(lambda (cc)
(let loop ((cc cc) (state 0))
(printf "IN THREAD ~A TYPE: NO-EXIT STATE: ~A~N" label state)
(loop (call/cc cc) (+ state 1))))))
(no-reps
(lambda (label data)
;breaks it for some reason?
;would be called, do its stuff and then
;go back to the calling continuation
(lambda (cc)
(printf "IN THREAD ~A TYPE: NO-REPS~N" label)
(call/cc cc)))))
(spawn-thread main 'main 10
(spawn-thread with-exit 1 '())
(spawn-thread no-exit 2 '())
(spawn-thread with-exit 3 '())
;(spawn-thread no-reps 4 '())) uncomment to see error
))
So whats up with no-reps? why does running it as one of the threads in main lead to an infinite loop?
output from example with commented line:
IN THREAD 1 TYPE: WITH-EXIT STATE: 0
IN THREAD 2 TYPE: NO-EXIT STATE: 0
IN THREAD 3 TYPE: WITH-EXIT STATE: 0
IN MAIN THREAD STATE: 0
---IN THREAD 1 TYPE: WITH-EXIT STATE: 1
IN MAIN THREAD STATE: 1
---IN THREAD 2 TYPE: NO-EXIT STATE: 1
IN MAIN THREAD STATE: 2
---IN THREAD 3 TYPE: WITH-EXIT STATE: 1
IN MAIN THREAD STATE: 3
---IN THREAD 1 TYPE: WITH-EXIT STATE: 2
IN MAIN THREAD STATE: 4
---IN THREAD 2 TYPE: NO-EXIT STATE: 2
IN MAIN THREAD STATE: 5
---IN THREAD 3 TYPE: WITH-EXIT STATE: 2
IN MAIN THREAD STATE: 6
---IN THREAD 1 TYPE: WITH-EXIT STATE: 3
IN MAIN THREAD STATE: 7
---IN THREAD 2 TYPE: NO-EXIT STATE: 3
IN MAIN THREAD STATE: 8
---IN THREAD 3 TYPE: WITH-EXIT STATE: 3
IN MAIN THREAD STATE: 9
---IN THREAD 1 TYPE: WITH-EXIT STATE: 4
IN MAIN THREAD STATE: 10
Uncommented:
IN THREAD 1 TYPE: WITH-EXIT STATE: 0
IN THREAD 2 TYPE: NO-EXIT STATE: 0
IN THREAD 3 TYPE: WITH-EXIT STATE: 0
IN THREAD 4 TYPE: NO-REPS
IN MAIN THREAD STATE: 0
---IN THREAD 1 TYPE: WITH-EXIT STATE: 1
IN MAIN THREAD STATE: 1
---IN THREAD 2 TYPE: NO-EXIT STATE: 1
IN MAIN THREAD STATE: 2
---IN THREAD 3 TYPE: WITH-EXIT STATE: 1
IN MAIN THREAD STATE: 3
---IN MAIN THREAD STATE: 0
---IN THREAD 1 TYPE: WITH-EXIT STATE: 1
......... ;profit????

Not sure which implementation you are using, but I couldn't get infinite loop just uncommenting the expression. (I've used couple of R6RS implementations, including Racket.)
To make things easier, I've stripped your code like this:
#!r6rs
(import (rnrs))
(define (print . args) (for-each display args) (newline))
(let ((spawn-thread
(lambda (it . args)
(call/cc (apply it args))))
(main
(lambda (label reps . sequence)
(lambda (cc)
(print sequence)
(let loop ((sequence sequence) (state 0))
(print "IN MAIN THREAD STATE: " state)
(display "---")
(if (< state reps)
(let ((next `(,#(cdr sequence) ,(call/cc (car sequence))) ))
(loop next (+ state 1))))))))
(no-reps
(lambda (label data)
(lambda (cc)
(print "IN THREAD "label" TYPE: NO-REPS")
(call/cc cc)))))
(spawn-thread main 'main 10
;; *1
(spawn-thread no-reps 4 '())))
The point is the returning continuation of *1. The procedure spawn-thread executes the no-reps procedure, and no-reps returns the given continuation whose next process is calling spawn-thread of main. Thus, what no-reps actually does in this context is duplicating the main thread. The following execution result, run on Racket, shows it:
IN THREAD 4 TYPE: NO-REPS
{#<continuation>}
IN MAIN THREAD STATE: 0
---{#<continuation>}
IN MAIN THREAD STATE: 0
---IN MAIN THREAD STATE: 1
---IN MAIN THREAD STATE: 1
---IN MAIN THREAD STATE: 2
---IN MAIN THREAD STATE: 2
---IN MAIN THREAD STATE: 3
---IN MAIN THREAD STATE: 3
---IN MAIN THREAD STATE: 4
---IN MAIN THREAD STATE: 4
---IN MAIN THREAD STATE: 5
---IN MAIN THREAD STATE: 5
---IN MAIN THREAD STATE: 6
---IN MAIN THREAD STATE: 6
---IN MAIN THREAD STATE: 7
---IN MAIN THREAD STATE: 7
---IN MAIN THREAD STATE: 8
---IN MAIN THREAD STATE: 8
---IN MAIN THREAD STATE: 9
---IN MAIN THREAD STATE: 9
---IN MAIN THREAD STATE: 10
---%

Related

is there any way to get the start time of the thread in gdb core dump

i am trying to find oldest thread in Linux core dump. So i need get start time of each thread that are running. So is there any way to get the start time of thread.
i tried to some command in gdb core file but that gives each call stack of threads but not start time.
Regards
Rabi
i am trying to find oldest thread in Linux core dump. So i need get start time of each thread that are running.
Your conclusion does not follow from your previous statement.
So is there any way to get the start time of thread.
No: that time is not recorded anywhere in the thread structure.
However, in general Linux allocates thread ids in increasing order, so sorting by thread id should give you the order you desire. For example:
(gdb) info thread
Id Target Id Frame
* 1 Thread 0x7fa91e769740 (LWP 2128629) __GI_raise (sig=sig#entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
2 Thread 0x7fa91d766700 (LWP 2128632) 0x0000557aa5787165 in fn ()
3 Thread 0x7fa91af61700 (LWP 2128637) 0x0000557aa5787165 in fn ()
4 Thread 0x7fa91df67700 (LWP 2128631) 0x0000557aa5787165 in fn ()
5 Thread 0x7fa91cf65700 (LWP 2128633) 0x0000557aa5787165 in fn ()
6 Thread 0x7fa91bf63700 (LWP 2128635) 0x0000557aa5787165 in fn ()
7 Thread 0x7fa91c764700 (LWP 2128634) 0x0000557aa5787165 in fn ()
8 Thread 0x7fa91a760700 (LWP 2128638) 0x0000557aa5787165 in fn ()
9 Thread 0x7fa91b762700 (LWP 2128636) 0x0000557aa5787165 in fn ()
10 Thread 0x7fa919f5f700 (LWP 2128639) 0x0000557aa5787165 in fn ()
Here you can see that thread 1 was created first, followed by thread 4, 2, 5, 7, etc (LWP is the Linux thread id here).

How to change executing thread in gdb?

I'm currently debugging kernel code using KGDB.
Whenever I break in I naturally jump to the interrupt handler for kgdb.
Under GDB I ran the following command.
info threads
and the output would be
7 Thread 7 (rcu_sched) 0x0000000000000000 in irq_stack_union ()
6 Thread 5 (kworker/0:0H) 0x0000000000000000 in irq_stack_union ()
5 Thread 3 (ksoftirqd/0) 0x0000000000000000 in irq_stack_union ()
4 Thread 2 (kthreadd) 0x0000000000000000 in irq_stack_union ()
3 Thread 1 (init) 0x0000000000000000 in irq_stack_union ()
2 Thread 3754 (Xorg) 0x0000000000000000 in irq_stack_union ()
* 1 Thread 4294967294 (shadowCPU0) kgdb_breakpoint ()
at kernel/debug/debug_core.c:1042
I would then jump through the code expecting to end up in a different thread (I'm interested in Xorg) however after i step through the code the next executing thread becomes cpu idle.
info thread
* 1 Thread 4294967294 (shadowCPU0) cpu_idle_loop () at kernel/cpu/idle.c:116
How can I switch my debug context to Xorg or any other thread, additionally what does irq_stack_union () mean. Thread is idle pending interrupts?
According to the offical documentation is is just thread threadno
https://sourceware.org/gdb/onlinedocs/gdb/Threads.html

Number of times the waiting thread will be executed

Suppose I have two thread T1 and T1.
Thread T1 will call t1_callback() and T2 is calling t2_callback().
T some_global_data;
pthread_mutex_t mutex;
void t1_callback()
{
pthread_mutex_lock(&mutex);
update_global_data(some_global_data);
pthread_mutex_unlock(&mutex);
}
void t2_callback()
{
pthread_mutex_lock(&mutex);
update_global_data(some_global_data);
pthread_mutex_unlock(&mutex);
}
Case
t1_callback() is holding the lock between time (t1 - t2).
In between this time (t1 - t2), if t2_callback has been called for say 10 times.
Question
Then how many times will t2_callback() will be executed, when t1_callback() release the mutex.
If a thread calls t2_callback() while another thread is executing t1_callback() and holding the lock, it (the thread running t2_callback()) will be suspended in pthread_mutex_lock(); until the lock is released. So it doesn't make sense to talk about one thread calling t2_callback() 10 times while the lock is held.
If 10 different threads all call t2_callback() in that time, they'll all be suspended in pthread_mutex_lock();, and they will each proceed one-at-a-time when the lock is released.

OpenMP: Divide all the threads into different groups

I will like to divide all the threads into 2 different groups, since I have two parallel tasks to run asynchronously. For example, if totally 8 threads are available, I will like 6 threads dedicated to task1, and the other 2 dedicated to task2.
How can I achieve this with OpenMP?
This is a job for OpenMP nested parallelism, as of OpenMP 3: you can use OpenMP tasks to start two independent tasks and then within those tasks, have parallel sections which use the appropriate number of threads.
As a quick example:
#include <stdio.h>
#include <omp.h>
int main(int argc, char **argv) {
omp_set_nested(1); /* make sure nested parallism is on */
int nprocs = omp_get_num_procs();
int nthreads1 = nprocs/3;
int nthreads2 = nprocs - nthreads1;
#pragma omp parallel default(none) shared(nthreads1, nthreads2) num_threads(2)
#pragma omp single
{
#pragma omp task
#pragma omp parallel for num_threads(nthreads1)
for (int i=0; i<16; i++)
printf("Task 1: thread %d of the %d children of %d: handling iter %d\n",
omp_get_thread_num(), omp_get_team_size(2),
omp_get_ancestor_thread_num(1), i);
#pragma omp task
#pragma omp parallel for num_threads(nthreads2)
for (int j=0; j<16; j++)
printf("Task 2: thread %d of the %d children of %d: handling iter %d\n",
omp_get_thread_num(), omp_get_team_size(2),
omp_get_ancestor_thread_num(1), j);
}
return 0;
}
Running this on an 8 core (16 hardware threads) node,
$ gcc -fopenmp nested.c -o nested -std=c99
$ ./nested
Task 2: thread 3 of the 11 children of 0: handling iter 6
Task 2: thread 3 of the 11 children of 0: handling iter 7
Task 2: thread 1 of the 11 children of 0: handling iter 2
Task 2: thread 1 of the 11 children of 0: handling iter 3
Task 1: thread 2 of the 5 children of 1: handling iter 8
Task 1: thread 2 of the 5 children of 1: handling iter 9
Task 1: thread 2 of the 5 children of 1: handling iter 10
Task 1: thread 2 of the 5 children of 1: handling iter 11
Task 2: thread 6 of the 11 children of 0: handling iter 12
Task 2: thread 6 of the 11 children of 0: handling iter 13
Task 1: thread 0 of the 5 children of 1: handling iter 0
Task 1: thread 0 of the 5 children of 1: handling iter 1
Task 1: thread 0 of the 5 children of 1: handling iter 2
Task 1: thread 0 of the 5 children of 1: handling iter 3
Task 2: thread 5 of the 11 children of 0: handling iter 10
Task 2: thread 5 of the 11 children of 0: handling iter 11
Task 2: thread 0 of the 11 children of 0: handling iter 0
Task 2: thread 0 of the 11 children of 0: handling iter 1
Task 2: thread 2 of the 11 children of 0: handling iter 4
Task 2: thread 2 of the 11 children of 0: handling iter 5
Task 1: thread 1 of the 5 children of 1: handling iter 4
Task 2: thread 4 of the 11 children of 0: handling iter 8
Task 2: thread 4 of the 11 children of 0: handling iter 9
Task 1: thread 3 of the 5 children of 1: handling iter 12
Task 1: thread 3 of the 5 children of 1: handling iter 13
Task 1: thread 3 of the 5 children of 1: handling iter 14
Task 2: thread 7 of the 11 children of 0: handling iter 14
Task 2: thread 7 of the 11 children of 0: handling iter 15
Task 1: thread 1 of the 5 children of 1: handling iter 5
Task 1: thread 1 of the 5 children of 1: handling iter 6
Task 1: thread 1 of the 5 children of 1: handling iter 7
Task 1: thread 3 of the 5 children of 1: handling iter 15
Updated: I've changed the above to include the thread ancestor; there was come confusion because there were (for instance) two "thread 1"s printed - here I've also printed the ancestor (e.g., "thread 1 of the 5 children of 1" vs "thread 1 of the 11 children of 0").
From the OpenMP standard, S.3.2.4, “The omp_get_thread_num routine returns the thread number, within the current team, of the calling thread.”, and from section 2.5, “When a thread encounters a parallel construct, a team of threads is created to
execute the parallel region [...] The thread that encountered the parallel construct
becomes the master thread of the new team, with a thread number of zero for the
duration of the new parallel region.”
That is, within each of those (nested) parallel regions, teams of threads are created which have thread ids starting at zero; but just because those ids overlap within the team doesn't mean they're the same threads. Here I've emphasized that by printing their ancestor number as well, but if the threads were doing CPU-intensive work you'd also see with monitoring tools that there were indeed 16 active threads, not just 11.
The reason why they are team-local thread numbers and not globally-unique thread numbers is pretty straightforward; it would be almost impossible to keep track of globally-unique thread numbers in an environment where nested and dynamic parallelism can happen. Say there are three teams of threads, numbered [0..5], [6,..10], and [11..15], and the middle team completes. Do we leave gaps in the thread numbering? do we interrupt all threads to change their global numbers? What if a new team is started, with 7 threads? Do we start them at 6 and have overlapping thread ids, or do we start them at 16 and leave gaps in the numbering?

what's the detail about gdb, does it hold one thread?

What's the detail about gdb, does it hold one thread when debugging code?
I set an exit flag in the main thread, and I have joined other threads before printing the flag. When I run the debug version using gdb after compiling with argument "-g", it looks:
[Thread debugging using libthread_db enabled]
Input number of threads:5
Main thread id: 0xb7fda6c0,
[New Thread 0xb7fd9b70 (LWP 9276)]
[New Thread 0xb75d8b70 (LWP 9277)]
[New Thread 0xb6bd7b70 (LWP 9278)]
[New Thread 0xb61d6b70 (LWP 9279)]
[New Thread 0xb57d5b70 (LWP 9280)]
I am thread 0xb6bd7b70, myorder 2, thread_exit.
I am thread 0xb61d6b70, myorder 3, thread_exit.
I am thread 0xb7fd9b70, myorder 0, thread_exit.
I am thread 0xb57d5b70, myorder 4, thread_exit.
I am thread 0xb75d8b70, myorder 1, thread_exit.
[Thread 0xb61d6b70 (LWP 9279) exited]
[Thread 0xb6bd7b70 (LWP 9278) exited]
[Thread 0xb75d8b70 (LWP 9277) exited]
[Thread 0xb7fd9b70 (LWP 9276) exited]
Main: completed join with thread 0xb7fd9b70 having a status of 0
Main: completed join with thread 0xb75d8b70 having a status of 1
Main: completed join with thread 0xb6bd7b70 having a status of 2
Main: completed join with thread 0xb61d6b70 having a status of 3
Main: completed join with thread 0xb57d5b70 having a status of 4
Main: lock will be destroy
Main: 9273, tlist will be free
Main exit.
[Thread 0xb57d5b70 (LWP 9280) exited]
Program exited normally.
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.7.el6.i686 libgcc-4.4.4-13.el6.i686
GDB gives information about the "create" and "exit" of threads. But there is always one thread exited after calling pthread_join() and printing "Main exit" in main thread. Why? Is the thread which gdb work with?
Run the release edition, nothing special:
Input number of threads:5
Main thread id: 0xb77176c0,
I am thread 0xb5913b70, myorder 3, thread_exit.
I am thread 0xb4f12b70, myorder 4, thread_exit.
I am thread 0xb6314b70, myorder 2, thread_exit.
I am thread 0xb6d15b70, myorder 1, thread_exit.
I am thread 0xb7716b70, myorder 0, thread_exit.
Main: completed join with thread 0xb7716b70 having a status of 0
Main: completed join with thread 0xb6d15b70 having a status of 1
Main: completed join with thread 0xb6314b70 having a status of 2
Main: completed join with thread 0xb5913b70 having a status of 3
Main: completed join with thread 0xb4f12b70 having a status of 4
Main: lock will be destroy
Main: tdata list will be free
Main exit.
gdb, does it hold one thread when debug code?
No.
there is always one thread exited after calling pthread_join() and printing "Main exit" in main thread. Why?
The notification that glibc sends to GDB to tell it that a thread has exited is sent as (nearly) the last thing a thread does. In particular, that notification is sent after the exiting thread has notified the main thread that it has exited (i.e. after the exiting thread wakes the main thread). Therefore, it's not at all surprising that main thread wakes up and prints Main exit before GDB notices that the exiting thread has in fact exited.
I have run it many times, there is only one thread after "Main exit" for each time.
That proves nothing. If you run your program 1,000,000 times, there will probably be at least one run where GDB will notice the thread exiting before Main exit is printed. The ordering is likely dependent on how many processors your system has, and how busy they are. There is really nothing (interesting) to see here.

Resources