Red Hat Training

A Red Hat training course is available for Red Hat Enterprise Linux

4.3.5. Debugging Individual Threads

GDB has the ability to debug individual threads, and to manipulate and examine them independently. This functionality is not enabled by default. To do so use set non-stop on and set target-async on. These can be added to .gdbinit. Once that functionality is turned on, GDB is ready to conduct thread debugging.
For example, the following program creates two threads. These two threads, along with the original thread executing main makes a total of three threads.
three-threads.c

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

pthread_t thread;

void* thread3 (void* d)
{
  int count3 = 0;

  while(count3 < 1000){
    sleep(10);
    printf("Thread 3: %d\n", count3++);
  }
  return NULL;
}

void* thread2 (void* d)
{
  int count2 = 0;

  while(count2 < 1000){
    printf("Thread 2: %d\n", count2++);
  }
  return NULL;
}

int main (){

  pthread_create (&thread, NULL, thread2, NULL);
  pthread_create (&thread, NULL, thread3, NULL);
  
  //Thread 1
  int count1 = 0;

  while(count1 < 1000){
    printf("Thread 1: %d\n", count1++);
  }

  pthread_join(thread,NULL);
  return 0;
}

Compile this program in order to examine it under GDB.
gcc -g three-threads.c -o three-threads  -lpthread
gdb ./three-threads
First set breakpoints on all thread functions; thread1, thread2, and main.
(gdb) break thread3
Breakpoint 1 at 0x4006c0: file three-threads.c, line 9.
(gdb) break thread2
Breakpoint 2 at 0x40070c: file three-threads.c, line 20.
(gdb) break main
Breakpoint 3 at 0x40074a: file three-threads.c, line 30.
Then run the program.
(gdb) run
[...]
Breakpoint 3, main () at three-threads.c:30
30	  pthread_create (&thread, NULL, thread2, NULL);
[...]
(gdb) info threads
* 1 Thread 0x7ffff7fd5720 (LWP 4620)  main () at three-threads.c:30
(gdb) 

Note that the command info threads provides a summary of the program's threads and some details about their current state. In this case there is only one thread that has been created so far.
Continue execution some more.
(gdb) next
[New Thread 0x7ffff7fd3710 (LWP 4687)]
31	  pthread_create (&thread, NULL, thread3, NULL);
(gdb) 
Breakpoint 2, thread2 (d=0x0) at three-threads.c:20
20	  int count2 = 0;
next
[New Thread 0x7ffff75d2710 (LWP 4688)]
34	  int count1 = 0;
(gdb) 
Breakpoint 1, thread3 (d=0x0) at three-threads.c:9
9	  int count3 = 0;
info threads
  3 Thread 0x7ffff75d2710 (LWP 4688)  thread3 (d=0x0) at three-threads.c:9
  2 Thread 0x7ffff7fd3710 (LWP 4687)  thread2 (d=0x0) at three-threads.c:20
* 1 Thread 0x7ffff7fd5720 (LWP 4620)  main () at three-threads.c:34

Here, two more threads are created. The star indicates the thread currently under focus. Also, the newly created threads have hit the breakpoint set for them in their initialization functions. Namely, thread2() and thread3().
To begin real thread debugging, use the thread <thread number> command to switch the focus to another thread.
(gdb) thread 2
[Switching to thread 2 (Thread 0x7ffff7fd3710 (LWP 4687))]#0  thread2 (d=0x0)
    at three-threads.c:20
20	  int count2 = 0;
(gdb) list
15	  return NULL;
16	}
17	
18	void* thread2 (void* d)
19	{
20	  int count2 = 0;
21	
22	  while(count2 < 1000){
23	    printf("Thread 2: %d\n", count2++);
24	  }
Thread 2 stopped at line 20 in its function thread2().
(gdb) next
22	  while(count2 < 1000){
(gdb) print count2
$1 = 0
(gdb) next
23	    printf("Thread 2: %d\n", count2++);
(gdb) next
Thread 2: 0
22	  while(count2 < 1000){
(gdb) next
23	    printf("Thread 2: %d\n", count2++);
(gdb) print count2
$2 = 1
(gdb) info threads
  3 Thread 0x7ffff75d2710 (LWP 4688)  thread3 (d=0x0) at three-threads.c:9
* 2 Thread 0x7ffff7fd3710 (LWP 4687)  thread2 (d=0x0) at three-threads.c:23
  1 Thread 0x7ffff7fd5720 (LWP 4620)  main () at three-threads.c:34
(gdb) 
Above, a few lines of thread2 printed the counter count2 and left thread 2 at line 23 as is seen by the output of 'info threads'.
Now thread3.
(gdb) thread 3
[Switching to thread 3 (Thread 0x7ffff75d2710 (LWP 4688))]#0  thread3 (d=0x0)
    at three-threads.c:9
9	  int count3 = 0;
(gdb) list
4	
5	pthread_t thread;
6	
7	void* thread3 (void* d)
8	{
9	  int count3 = 0;
10	
11	  while(count3 < 1000){
12	    sleep(10);
13	    printf("Thread 3: %d\n", count3++);
(gdb) 
Thread three is a little different in that it has a sleep statement and executes slowly. Think of it as a representation of an uninteresting IO thread. Because this thread is uninteresting, continue its execution uninterrupted, using the continue.
(gdb) continue &
(gdb) Thread 3: 0
Thread 3: 1
Thread 3: 2
Thread 3: 3
Take note of the & at the end of the continue. This allows the GDB prompt to return so other commands can be executed. Using the interrupt, execution can be stopped should thread 3 become interesting again.
(gdb) interrupt
[Thread 0x7ffff75d2710 (LWP 4688)] #3 stopped.
0x000000343f4a6a6d in nanosleep () at ../sysdeps/unix/syscall-template.S:82
82	T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
It is also possible to go back to the original main thread and examine it some more.
(gdb) thread 1
[Switching to thread 1 (Thread 0x7ffff7fd5720 (LWP 4620))]#0  main ()
    at three-threads.c:34
34	  int count1 = 0;
(gdb) next
36	  while(count1 < 1000){
(gdb) next
37	    printf("Thread 1: %d\n", count1++);
(gdb) next
Thread 1: 0
36	  while(count1 < 1000){
(gdb) next
37	    printf("Thread 1: %d\n", count1++);
(gdb) next
Thread 1: 1
36	  while(count1 < 1000){
(gdb) next
37	    printf("Thread 1: %d\n", count1++);
(gdb) next
Thread 1: 2
36	  while(count1 < 1000){
(gdb) print count1 
$3 = 3
(gdb) info threads 
  3 Thread 0x7ffff75d2710 (LWP 4688)  0x000000343f4a6a6d in nanosleep ()
    at ../sysdeps/unix/syscall-template.S:82
  2 Thread 0x7ffff7fd3710 (LWP 4687)  thread2 (d=0x0) at three-threads.c:23
* 1 Thread 0x7ffff7fd5720 (LWP 4620)  main () at three-threads.c:36
(gdb) 
As can be seen from the output of info threads, the other threads are where they were left, unaffected by the debugging of thread 1.