在信号量测试时,常常需要创建多个线程,比如生产者-消费者问题中,需要模拟多个生产者、多个消费者。

pthreads是指POSIX threads。

1. 一个简单例子

创建10个线程,每个线程打印出自己的线程ID,

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

#define NUM_THREADS 10

void *do_something(void *arg)
{
    printf("%d \t Thread ID %ld\n", *(int *)arg, pthread_self());
    sleep(2);
}

int main()
{
    pthread_t thread_id[NUM_THREADS];
    for (int i=0; i<NUM_THREADS; i++){
        int retval = pthread_create(&thread_id[i], NULL, do_something, &i);
        if (0 != retval){
            printf("%d \t return value: %d\n", i, retval);
            perror("pthread_create error.");
            return -1;
        }

    }

    // wait for the threads to terminate
    for (int i=0; i<NUM_THREADS; i++){
        if (0 != pthread_join(thread_id[i], NULL)){
            perror("pthread_join error.");
        }
    }

    return 0;
}

2. 线程创建pthread_create

线程创建函数:pthread_create(3) - Linux manual page

#include <pthread.h>

int pthread_create(pthread_t *thread, 
                   const pthread_attr_t *attr,
                   void *(*start_routine) (void *), 
                   void *arg);
  • pthread_t *thread,线程创建后返回的线程ID,类型实为unsigned long int
  • void *(*start_routine) (void *),是一个函数指数,线程执行的代码
  • void *arg,传给线程函数start_routine的参数,只能一个

pthread_create创建的线程默认是joinable,可以调用pthread_join函数。

3. pthread_join

pthread_join(3) - Linux manual page

#include <pthread.h>

int pthread_join(pthread_t thread, void **retval);

等待线程thread终止,retval 是线程thread的返回值。

(1)如果没有pthread_join

如果主线程没有调用pthread_join,试想这么一种情况,新创建的线程需要进行耗时的计算操作,那么主线程退出了,新创建的线程尚未运行结束。

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

#define NUM_THREADS 10

void *do_something(void *arg)
{
    printf("%d \t Thread ID %ld\n", *(int *)arg, pthread_self());
    sleep(2);
}


int main()
{
    pthread_t thread_id[NUM_THREADS];
    for (int i=0; i<NUM_THREADS; i++){
        int retval = pthread_create(&thread_id[i], NULL, do_something, &i);
        if (0 != retval){
            printf("%d \t return value: %d\n", i, retval);
            perror("pthread_create error.");
            return -1;
        }
    }

    return 0;
}

运行结果如下,

root@jmu-cs:~/os_exp/exp5_mutex_pv_log_bridge# ./pthread_example
4        Thread ID 140002933835520
8        Thread ID 140002875086592
9        Thread ID 140002866693888
5root@jmu-cs:~/os_exp/exp5_mutex_pv_log_bridge# ./pthread_example
4        Thread ID 139747523970816
5        Thread ID 139747490400000
6        Thread ID 139747482007296
6        Thread ID 139747498792704
9        Thread ID 139747456829184
root@jmu-cs:~/os_exp/exp5_mutex_pv_log_bridge# ./pthread_example
4        Thread ID 140158325679872
5        Thread ID 140158292109056
6        Thread ID 140158283716352

可以看见,创建了10个线程,但并没有每个进程都得到运行,这是因为主线程运行结束退出了。除此之外,每次运行的结果还不同(取决于调度)。

(2)加上pthread_join

现在来看下,加上pthread_join,会怎样,在上述代码return 0;之前加上,

// wait for the threads to terminate
for (int i=0; i<NUM_THREADS; i++){
    pthread_join(thread_id[i], NULL);
}

运行结果如下,每个线程都得到了执行。

root@jmu-cs:~/os_exp/exp5_mutex_pv_log_bridge# ./pthread_example
4        Thread ID 139964125910784
9        Thread ID 139964075554560
5        Thread ID 139964117518080
10       Thread ID 139963983193856
6        Thread ID 139964100732672
6        Thread ID 139964083947264
7        Thread ID 139964092339968
10       Thread ID 139963991586560
5        Thread ID 139964109125376
10       Thread ID 139964067161856

注:创建线程后,线程如果没有被pthread_join,线程结束,会有一部分资源没有被回收。

4. pthread_detach

pthread_detach(3) - Linux manual page

#include <pthread.h>

int pthread_detach(pthread_t thread);

调用pthread_detachthread会被标记为detached,新线程结束后,资源会自动释放。

调用pthread_join,新进程没有运行结束,调用者会被阻塞,有些应用并不希望如此。举例,计算机网络中,服务器通常有一个主线程监听某个端口,接收请求,并创建一个线程去处理该请求,这种情况,主线程并不希望阻塞在处理请求的进程上。应对这种情况,可以调用pthread_detach,将新线程剥离出来。

5. 获取线程的ID

获取线程ID函数:pthread_self(3) - Linux manual page

#include <pthread.h>

pthread_t pthread_self(void);

6. 终止线程pthread_exit

pthread_exit(3) - Linux manual page

#include <pthread.h>

noreturn void pthread_exit(void *retval);

终止调用者线程。

本文系Spark & Shine原创,转载需注明出处本文最近一次修改时间 2023-04-27 17:20

results matching ""

    No results matching ""