First taste of C thread APIs

Since C11, C provides standard thread APIs like what C++ does. It means technically, you should use C‘s standard thread APIs to do multi-thread stuff, not pthread APIs. Below is a simple example:

#include <threads.h>
#include <stdio.h>

int print_thread(void* s)
{
    printf("%s\n", (char*)s);
    thrd_exit(0);
}
int main()
{
    thrd_t tid;
    if (thrd_success != thrd_create(&tid, print_thread, "Hello world"))
    {
        fprintf(stderr, "Create thread error\n");
        return 1;
    }
    thrd_join(tid, NULL);
    return 0;
}

Check thrd_create implementation in glibc:

#include "thrd_priv.h"

int
thrd_create (thrd_t *thr, thrd_start_t func, void *arg)
{
  _Static_assert (sizeof (thr) == sizeof (pthread_t),
          "sizeof (thr) != sizeof (pthread_t)");

  int err_code = __pthread_create_2_1 (thr, ATTR_C11_THREAD,
                       (void* (*) (void*))func, arg);
  return thrd_err_map (err_code);
}

You can see thrd_create just encapsulates __pthread_create_2_1, so you can guess in glibc, the standard C thread APIs are just wrappers of pthreadimplementation. It means you need to link pthread library during compiling. Otherwise you will meet following errors:

main.c:(.text+0x1e): undefined reference to `thrd_exit'
......
main.c:(.text+0x4f): undefined reference to `thrd_create'
/usr/bin/ld: main.c:(.text+0x60): undefined reference to `thrd_join'

P.S., the full code is here.

Access thread information on Dragonfly BSD

On Dragonfly BSD, even it already provides pseudo proc file system, you can’t access thread information like Linux (/proc/$pid/task). You still need to use kvm:

......
kvm_t* kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
......
struct kinfo_proc *proc = kvm_getprocs(
                                kd,
                                KERN_PROC_PID | KERN_PROC_FLAG_LWP,
                                (int)(pid),
                                &cnt);
......
kvm_close(kd); 

According to man:

The number of processes found is returned in the reference parameter cnt. The processes are returned as a contiguous array of kinfo_proc structures.

There is kp_lwp member in kinfo_proc structure which records information of this thread, i.e., LWP. E.g., To print every thread’s ID:

......
printf("Process (%s) has %d threads, and LWP IDs are:\n", argv[1], cnt);
for (int i = 0; i < cnt; i++)
{
    printf("%d\n",  proc[i].kp_lwp.kl_tid);
}
......

For other BSDs, the principle may be similar.

P.S., the full code is here.

Display running process’s thread IDs on Linux

On Linux, “ps -T” can show threads information of running process:

# ps -T 2739
  PID  SPID TTY      STAT   TIME COMMAND
 2739  2739 pts/0    Sl     0:00 ./spawn_threads
 2739  2740 pts/0    Sl     0:00 ./spawn_threads
 2739  2741 pts/0    Sl     0:00 ./spawn_threads

On proc pseudo file system, there is a task directory which records thread information:

# ls -lt /proc/2739/task
total 0
dr-xr-xr-x 7 root root 0 Jun 28 14:55 2739
dr-xr-xr-x 7 root root 0 Jun 28 14:55 2740
dr-xr-xr-x 7 root root 0 Jun 28 14:55 2741

Since C++17, there is a filesystem library which can be used to access file system, and I leverage this library to traverse the /proc/$pid/task folder to get the thread IDs of process:

    ......
    std::filesystem::path p{"/proc"};
    p /= argv[1];
    p /= "task";
    ......
    uint64_t thread_num{};
    std::vector<std::string> thread_id;

    std::filesystem::directory_iterator d_it(p);
    for (const auto& it : d_it)
    {
        thread_num++;
        thread_id.push_back(it.path().filename().string());
    }

    std::cout << "Process ID (" << argv[1] << ") has " << thread_num << " threads, and ids are:\n";
    for (const auto& v : thread_id)
    {
        std::cout << v << '\n';
    }
    ......

Build and run it:

# ./show_thread_ids 2739
Process ID (2739) has 3 threads, and ids are:
2739
2740
2741

P.S., the full code is here.

Be ware of HElib and corresponding NTL versions

Today I tested an old HElib version (back to mid-2017), but met following compile errors:

......
In file included from EncryptedArray.cpp:15:
EncryptedArray.h:301:19: error: ‘FHE_DEFINE_LOWER_DISPATCH’ has not been declared
  301 |   NTL_FOREACH_ARG(FHE_DEFINE_LOWER_DISPATCH)
      |                   ^~~~~~~~~~~~~~~~~~~~~~~~~
EncryptedArray.h:303:3: error: ISO C++ forbids declaration of ‘NTL_FOREACH_ARG’ with no type [-fpermissive]
  303 |   const RX& getG() const { return mappingData.getG(); }
      |   ^~~~~
......

After some investigation, I found the problem was the NTL on my system is too new (version is 11.3.2). So I downloaded an old NTL version, and specified using this version in Makefile:

CFLAGS = -g -O2 -std=c++11 -I../../ntl-10.5.0/include ......

Then it worked like a charm!

Explore Dragonfly BSD thread model

From Dragonfly BSD‘s official document:

A user process contains one or more LWP (Light Weight Process) entities. Each entity represents a user thread under that process.

I want to explore the thread model myself. So I write a simple program which launches 2 threads in main function, and print process ID, LWP ID and thread id from C++‘s get_id function:

void output_thread_id(const std::string& prefix)
{
    std::stringstream ss;
    ss <<"Process ID is " << getpid() <<
        ", lwp ID is " << lwp_gettid() <<
        ", " << prefix << std::this_thread::get_id() <<'\n';
    std::cout << ss.str();
}

Build and run it:

# ./spawn_threads
Process ID is 16394, lwp ID is 1, main thread ID is 0x8007d00c0
Process ID is 16394, lwp ID is 2, sub thread ID is 0x8007d0240
Process ID is 16394, lwp ID is 3, sub thread ID is 0x8007d03c0

All 3 threads have same process ID, but LWP ID begins with 1, and increases contiguously (this is not same as Linux). By default, top command will only show processes:

Press ‘H‘ can display threads’ information (For ps command, -H option can be used to show threads):

P.S., the full code is here.

Reference:
How to get the thread number and every thread’s ID of a running process? .