pthread_create/join函数学习

转自:https://blog.csdn.net/wushuomin/article/details/80051295,chatgpt

1.pthread_create

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, 
                   void *(*start_routine)(void *), void *arg);

它的功能是创建线程(实际上就是确定调用该线程函数的入口点),在线程创建以后,就开始运行相关的线程函数。参数介绍:

*pthread_t thread:

  • 这是一个指向 pthread_t 类型变量的指针,pthread_t 是 POSIX 线程库中用于标识线程的类型。
  • pthread_create 函数会通过这个参数返回创建的线程 ID,后续可以使用这个 ID 来管理线程(如 pthread_join 等)。

*const pthread_attr_t attr:

  • 用于指定线程属性。如果传递 NULL,则使用默认属性。
  • 通过 pthread_attr_t 可以设置线程的属性,如是否使用守护线程(detached)、线程的栈大小等。

void *(*start_routine)(void *):

  • 这是线程函数的指针,即新线程创建后将要执行的函数。
  • 该函数必须返回一个 void*,并且接受一个 void* 作为参数,可以用于向线程传递参数(也就是第4个参数)。

*void arg:

  • 传递给线程函数的参数,可以是任何类型的指针。
  • 如果不需要参数,可以传递 NULL

pthread_create的返回值 表示成功,返回0;表示出错,返回表示-1。

例子:

#include 
#include 

void* thread_function(void* arg) {
    int* num = static_cast(arg); // 传参做类型转换
    std::cout << "Thread function received: " << *num << std::endl;
    return nullptr;
}

int main() {
    pthread_t thread;  // 线程标识符
    int arg = 42;      // 传递给线程的参数
    
    // 创建新线程
    if (pthread_create(&thread, nullptr, thread_function, &arg) != 0) {
        std::cerr << "Failed to create thread" << std::endl;
        return 1;
    }
    
    // 等待线程完成
    pthread_join(thread, nullptr);
    
    std::cout << "Thread has finished execution" << std::endl;
    return 0;
}

1.1 问题

内存泄漏问题:

在默认情况下通过pthread_create函数创建的线程是非分离属性的,由pthread_create函数的第二个参数决定,在非分离的情况下,当一个线程结束的时候,它所占用的系统资源并没有完全真正的释放,也没有真正终止。在大多数情况下,建议使用 pthread_join 等待线程完成。

对于结合的线程:

只有在pthread_join函数返回时,该线程才会释放自己的资源。或者是设置在分离属性的情况下,一个线程结束会立即释放它所占用的资源。

设置属性分离:

void run() { 
    return;
} 

int main(){ 
    pthread_t thread; 
    pthread_attr_t attr; 
    pthread_attr_init( &attr ); 
    pthread_attr_setdetachstate(&attr,1); 
    pthread_create(&thread, &attr, run, 0); //第二个参数决定了分离属性

    //...... 
    return 0; 
}

2.pthread_join

int pthread_join(
    pthread_t tid, //需要等待的线程,指定的线程必须位于当前的进程中,而且不得是分离线程
    void **status  //线程tid所执行的函数返回值(返回值地址需要保证有效),其中status可以为NULL
    );

pthreadlinux系统的默认库, 需手动链接-线程库 -lpthread

返回值:

  • 调用成功返回0.
  • ESRCH描述: 没有找到与给定的线程ID 相对应的线程。(如果多个线程等待同一个线程终止,则所有等待线程将一直等到目标线程终止。然后一个等待线程成功返回。其余的等待线程将失败返回ESRCH错误)
  • EDEADLK 描述: 将出现死锁,如一个线程等待其本身,或者线程A和线程B 互相等待。
  • EINVAL描述: 与给定的线程ID相对应的线程是分离线程。

pthread_join()函数会一直阻塞调用线程,直到指定的线程终止。当pthread_join()返回之后,应用程序可回收与已终止线程关联的任何数据存储空间

但是,同时需要注意,一定要和上面创建的某一线程配套使用,这样还可以起到互斥的作用。否则多线程可能抢占CPU资源,导致运行结果不确定。

//链接中举了个例子,非常好。

配套使用,使得线程执行顺序固定:(但这样就使得多线程变为了单线程执行。没什么意义了,类似函数调用?)

//这样才是按顺序的。
pthread_create(&t, 0, print1, NULL);
pthread_join(t, NULL);
pthread_create(&t1, 0, print2, NULL);
pthread_join(t1, NULL);
pthread_create(&t2, 0, print3, NULL);
pthread_join(t2, NULL);

3.join的作用 

https://www.jianshu.com/p/1007f0c13f7f,讲的非常好,代码例子,https://zhuanlan.zhihu.com/p/99374488

join()方法:Thread提供的让一个线程去等待另一个线程完成。

当在某个程序执行流中(如main线程)调用其它线程(如t2线程)的join方法(t2.join()),调用线程(main线程)将被阻塞,直到被join()方法加入的join线程(t2.start())执行完成为止。

join源码:

public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);//调用wait阻塞调用方
                now = System.currentTimeMillis() - base;
            }
        }
    }

 join方法的原理就是调用相应线程的wait方法进行等待操作的。例如:

  • A线程中调用了B线程的join方法,则相当于在A线程中调用了B线程的wait方法,
  • 当B线程执行完(或者到达等待时间),B线程会自动调用自身的notifyAll方法唤醒A线程,从而达到同步的目的。

多线程并行执行,每个线程先全部start再全部join;多个线程顺序执行,每个依次start然后join。

你可能感兴趣的:(java,jvm,开发语言)