何时使用pthread_exit()以及何时在linux中使用pthread_join()?

发布于 2025-02-09 15:29:58 字数 1585 浏览 2 评论 0 原文

我是Pthreads的新手,我正在尝试理解它。我看到了一些示例,如以下内容。

我可以看到 main()被API pthread_exit()阻止,并且我看到了示例,其中主函数被API pthread_join( )。我无法理解何时使用什么?

我指的是以下网站 - httpps://computing.llnl.gov/tutorials/pthreads/pthreads/ 。我无法获得何时使用 pthread_join()以及何时使用 pthread_exit()的概念。

有人可以解释吗?此外,将不胜感激的是Pthreads的良好教程链接。

#include <pthread.h>
#include <stdio.h>
#define NUM_THREADS     5

void *PrintHello(void *threadid)
{
   long tid;
   tid = (long)threadid;
   printf("Hello World! It's me, thread #%ld!\n", tid);
   pthread_exit(NULL);
}

int main (int argc, char *argv[])
{
   pthread_t threads[NUM_THREADS];
   int rc;
   long t;
   for(t=0; t<NUM_THREADS; t++){
      printf("In main: creating thread %ld\n", t);
      rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
      if (rc){
         printf("ERROR; return code from pthread_create() is %d\n", rc);
         exit(-1);
      }
   }

   /* Last thing that main() should do */
   pthread_exit(NULL);

有时会意识到另外一件事

pthread_cancel(thread);
pthread_join(thread, NULL);

,您想在执行线程时取消线程。 您可以使用pthread_cancel(thread);。 但是,请记住,您需要启用Pthread Cancel支持。 另外,取消时清理代码。

thread_cleanup_push(my_thread_cleanup_handler, resources);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);

static void my_thread_cleanup_handler(void *arg)
{
  // free
  // close, fclose
}

I am new to pthreads, and I am trying to understand it. I saw some examples like the following.

I could see that the main() is blocked by the API pthread_exit(), and I have seen examples where the main function is blocked by the API pthread_join(). I am not able to understand when to use what?

I am referring to the following site - https://computing.llnl.gov/tutorials/pthreads/. I am not able to get the concept of when to use pthread_join() and when to use pthread_exit().

Can somebody please explain? Also, a good tutorial link for pthreads will be appreciated.

#include <pthread.h>
#include <stdio.h>
#define NUM_THREADS     5

void *PrintHello(void *threadid)
{
   long tid;
   tid = (long)threadid;
   printf("Hello World! It's me, thread #%ld!\n", tid);
   pthread_exit(NULL);
}

int main (int argc, char *argv[])
{
   pthread_t threads[NUM_THREADS];
   int rc;
   long t;
   for(t=0; t<NUM_THREADS; t++){
      printf("In main: creating thread %ld\n", t);
      rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
      if (rc){
         printf("ERROR; return code from pthread_create() is %d\n", rc);
         exit(-1);
      }
   }

   /* Last thing that main() should do */
   pthread_exit(NULL);

Realized one more thing i.e.

pthread_cancel(thread);
pthread_join(thread, NULL);

Sometimes, you want to cancel the thread while it is executing.
You could do this using pthread_cancel(thread);.
However, remember that you need to enable pthread cancel support.
Also, a clean up code upon cancellation.

thread_cleanup_push(my_thread_cleanup_handler, resources);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);

static void my_thread_cleanup_handler(void *arg)
{
  // free
  // close, fclose
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

花期渐远 2025-02-16 15:29:59

唔。

After a thread has terminated, the result of access to local (auto) variables of the thread is 
undefined. Thus, references to local variables of the exiting thread should not be used for 
the pthread_exit() value_ptr parameter value.

这似乎与local main()螺纹变量保持可访问的想法背道而驰。

Hmm.

POSIX pthread_exit description from http://pubs.opengroup.org/onlinepubs/009604599/functions/pthread_exit.html:

After a thread has terminated, the result of access to local (auto) variables of the thread is 
undefined. Thus, references to local variables of the exiting thread should not be used for 
the pthread_exit() value_ptr parameter value.

Which seems contrary to the idea that local main() thread variables will remain accessible.

檐上三寸雪 2025-02-16 15:29:59

在主线程中使用 pthread_exit (代替 pthread_join ),将使主线程处于已倒闭(Zombie)状态。由于不使用 pthread_join ,因此终止的其他可加入线程也将保留在僵尸状态,并导致资源泄漏

未能加入可加入的线程(即,一个是
未分离),产生“僵尸线”。避免这样做,因为
每个僵尸线程都会消耗某些系统资源,并且有足够的时间
僵尸线程已经累积了,将不再有可能
创建新线程(或过程)。

另一点是将主线程保持在已停用状态,而其他线程正在运行时可能会在各种条件下导致相关问题,例如在主线程中分配了资源或在其他线程中使用的主线程局部变量。

同样,仅在流程退出时才会发布所有共享资源,它不能保存任何资源。因此,我认为应避免使用 PTHREAD_EXIT 代替 PTHREAD_JOIN

Using pthread_exit in the main thread(in place of pthread_join), will leave the main thread in defunct(zombie) state. Since not using pthread_join, other joinable threads which are terminated will also remain in the zombie state and cause resource leakage.

Failure to join with a thread that is joinable (i.e., one that is
not detached), produces a "zombie thread". Avoid doing this, since
each zombie thread consumes some system resources, and when enough
zombie threads have accumulated, it will no longer be possible to
create new threads (or processes).

Another point is keeping the main thread in the defunct state, while other threads are running may cause implementation dependent issues in various conditions like if resources are allocated in main thread or variables which are local to the main thread are used in other threads.

Also, all the shared resources are released only when the process exits, it's not saving any resources. So, I think using pthread_exit in place of pthread_join should be avoided.

所谓喜欢 2025-02-16 15:29:59

当调用pthread_exit()时,调用线程堆栈不再可作为任何其他线程的“活动”内存。所有其他线程仍然可以使用.DATA,.TEXT和.BSS部分“静态”内存分配。因此,如果您需要将某些内存值传递到pthread_exit()中,以使其其他一些pthread_join()呼叫者查看,则需要“可用”呼叫pthread_join()的线程。它应与malloc()/new分配,分配在pthread_join threads stack上,1)pthread_join呼叫者传递给pthread_create或以其他方式可用于the thread call pthread_exit()的堆栈值,或其他可用价值。

了解如何在线程堆栈之间管理内存,而值存储在.data/.bss内存部分中,这些内存用于存储宽值。

When pthread_exit() is called, the calling threads stack is no longer addressable as "active" memory for any other thread. The .data, .text and .bss parts of "static" memory allocations are still available to all other threads. Thus, if you need to pass some memory value into pthread_exit() for some other pthread_join() caller to see, it needs to be "available" for the thread calling pthread_join() to use. It should be allocated with malloc()/new, allocated on the pthread_join threads stack, 1) a stack value which the pthread_join caller passed to pthread_create or otherwise made available to the thread calling pthread_exit(), or 2) a static .bss allocated value.

It's vital to understand how memory is managed between a threads stack, and values store in .data/.bss memory sections which are used to store process wide values.

迷雾森÷林ヴ 2025-02-16 15:29:59
  #include<stdio.h>
  #include<pthread.h>
  #include<semaphore.h>
 
   sem_t st;
   void *fun_t(void *arg);
   void *fun_t(void *arg)
   {
       printf("Linux\n");
       sem_post(&st);
       //pthread_exit("Bye"); 
       while(1);
       pthread_exit("Bye");
   }
   int main()
   {
       pthread_t pt;
       void *res_t;
       if(pthread_create(&pt,NULL,fun_t,NULL) == -1)
           perror("pthread_create");
       if(sem_init(&st,0,0) != 0)
           perror("sem_init");
       if(sem_wait(&st) != 0)
           perror("sem_wait");
       printf("Sanoundry\n");
       //Try commenting out join here.
       if(pthread_join(pt,&res_t) == -1)
           perror("pthread_join");
       if(sem_destroy(&st) != 0)
           perror("sem_destroy");
       return 0;
   }

将此代码复制并粘贴到GDB上。在线GDB可以自己看。

确保您了解一旦创建线程,该过程与Main同时运行。

  1. 没有加入,主线程将继续运行并返回
  2. 加入,主线程将被卡在while循环中,因为它会等待执行线程。
  3. 通过加入并删除注释的PTHREAD_EXIT,该线程将在运行WILE循环和MAIN之前终止,将继续使用
  4. PTHREAD_EXIT的实际用途,可以用作条件或案例语句,以确保在退出之前运行某些代码的1个版本。
void *fun_t(void *arg)
   {
       printf("Linux\n");
       sem_post(&st); 
       if(2-1 == 1)  
           pthread_exit("Bye");
       else
       { 
           printf("We have a problem. Computer is bugged");
           pthread_exit("Bye"); //This is redundant since the thread will exit at the end
                                //of scope. But there are instances where you have a bunch
                                //of else if here.
       }
   }

我想证明有时您需要在此示例中首先使用信号量首先运行代码段。

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

sem_t st;

void* fun_t (void* arg)
{
    printf("I'm thread\n");
    sem_post(&st);
}

int main()
{
    pthread_t pt;
    pthread_create(&pt,NULL,fun_t,NULL);
    sem_init(&st,0,0);
    sem_wait(&st);
    printf("before_thread\n");
    pthread_join(pt,NULL);
    printf("After_thread\n");
    
}

注意到“在螺纹之前”之后,如果从上到下是线性在螺纹之前,我是线性的,我是线程,我是线程,螺纹之后。但是在这种情况下,我们阻止主运行进一步运行,直到func_t释放信号量为止。可以使用 https://www.onlinegdb.com/ 来验证结果。

  #include<stdio.h>
  #include<pthread.h>
  #include<semaphore.h>
 
   sem_t st;
   void *fun_t(void *arg);
   void *fun_t(void *arg)
   {
       printf("Linux\n");
       sem_post(&st);
       //pthread_exit("Bye"); 
       while(1);
       pthread_exit("Bye");
   }
   int main()
   {
       pthread_t pt;
       void *res_t;
       if(pthread_create(&pt,NULL,fun_t,NULL) == -1)
           perror("pthread_create");
       if(sem_init(&st,0,0) != 0)
           perror("sem_init");
       if(sem_wait(&st) != 0)
           perror("sem_wait");
       printf("Sanoundry\n");
       //Try commenting out join here.
       if(pthread_join(pt,&res_t) == -1)
           perror("pthread_join");
       if(sem_destroy(&st) != 0)
           perror("sem_destroy");
       return 0;
   }

Copy and paste this code on a gdb. Onlinegdb would work and see for yourself.

Make sure you understand once you have created a thread, the process run along with main together at the same time.

  1. Without the join, main thread continue to run and return 0
  2. With the join, main thread would be stuck in the while loop because it waits for the thread to be done executing.
  3. With the join and delete the commented out pthread_exit, the thread will terminate before running the while loop and main would continue
  4. Practical usage of pthread_exit can be used as an if conditions or case statements to ensure 1 version of some code runs before exiting.
void *fun_t(void *arg)
   {
       printf("Linux\n");
       sem_post(&st); 
       if(2-1 == 1)  
           pthread_exit("Bye");
       else
       { 
           printf("We have a problem. Computer is bugged");
           pthread_exit("Bye"); //This is redundant since the thread will exit at the end
                                //of scope. But there are instances where you have a bunch
                                //of else if here.
       }
   }

I would want to demonstrate how sometimes you would need to have a segment of code running first using semaphore in this example.

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

sem_t st;

void* fun_t (void* arg)
{
    printf("I'm thread\n");
    sem_post(&st);
}

int main()
{
    pthread_t pt;
    pthread_create(&pt,NULL,fun_t,NULL);
    sem_init(&st,0,0);
    sem_wait(&st);
    printf("before_thread\n");
    pthread_join(pt,NULL);
    printf("After_thread\n");
    
}

Noticed how fun_t is being ran after "before thread" The expected output if it is linear from top to bottom would be before thread, I'm thread, after thread. But under this circumstance, we block the main from running any further until the semaphore is released by func_t. The result can be verified with https://www.onlinegdb.com/

才能让你更想念 2025-02-16 15:29:58

如OpenPub文档中所述,

将退出调用它的线程。

在您的情况下,由于主要调用它,Main thread 将终止,而您的产卵线程将继续执行。这主要在
主线程仅需要产生线程并留下线程完成其作业


终止,否则暂停已调用它的线程的执行

除非目标线程
在主线程中处理。

As explained in the openpub documentations,

pthread_exit() will exit the thread that calls it.

In your case since the main calls it, main thread will terminate whereas your spawned threads will continue to execute. This is mostly used in cases where the
main thread is only required to spawn threads and leave the threads to do their job

pthread_join
will suspend execution of the thread that has called it unless the target thread terminates

This is useful in cases when you want to wait for thread/s to terminate before further
processing in main thread.

陪你到最终 2025-02-16 15:29:58

pthread_exit 终止调用线程时 pthread_join 暂停调用线程的执行,直到目标线程完成执行为止。

在开放组文档中对它们进行了详细的详细解释:

pthread_exit terminates the calling thread while pthread_join suspends execution of calling thread until target threads completes execution.

They are pretty much well explained in detail in the open group documentation:

你穿错了嫁妆 2025-02-16 15:29:58

两种方法都确保您的 Process 在所有线程结束之前都不会结束。

JOIN方法具有您的 main 函数的线程明确等待要“加入”的所有线程。

pthread_exit 方法以受控方式终止您的 MAIN 函数和线程。 main 具有以下特殊性:结束 main 否则将终止您的整个过程,包括所有其他线程。

为此,您必须确保任何线程都不使用其中声明的本地变量 main 函数。该方法的优点是您的 main 不必知道您过程中启动的所有线程,例如,其他线程本身就创建了 main 的新线程什么都不知道。

Both methods ensure that your process doesn't end before all of your threads have ended.

The join method has your thread of the main function explicitly wait for all threads that are to be "joined".

The pthread_exit method terminates your main function and thread in a controlled way. main has the particularity that ending main otherwise would be terminating your whole process including all other threads.

For this to work, you have to be sure that none of your threads is using local variables that are declared inside them main function. The advantage of that method is that your main doesn't have to know all threads that have been started in your process, e.g because other threads have themselves created new threads that main doesn't know anything about.

毁我热情 2025-02-16 15:29:58

PTHREAD_EXIT()API

如已经注释,用于调用线程终止。
打电话给该功能后,开始了复杂的清理机构。
完成线程后,线程将终止。
当对返回()例程的调用发生在PTHREAD_CREATE()创建的线程中时,PTHREAD_EXIT()API也被隐式称为。
实际上,返回()的调用和呼叫pthread_exit()具有相同的影响,是从pthread_create()创建的线程中调用的。

区分主()函数启动时隐含创建的初始线程以及由pthread_create()创建的线程。
从main()函数呼叫返回()例程隐式调用exit()系统调用,整个过程终止。
没有线程清理机制。
从main()函数对PTHREAD_EXIT()调用呼叫会导致清理机制启动并完成工作时,初始线程终止。

当pthread_exit()从main()函数调用PTHREAD实现时,整个过程(以及其他线程)发生了什么。
例如,在IBM OS/400实现上,当PTHREAD_EXIT()从main()函数调用PTHREAD_EXIT()时,整个过程终止了。
其他系统的行为可能会有所不同。
在大多数现代Linux机器上,从初始线程调用PTHREAD_EXIT()调用直到所有线程终止之前,都不会终止整个过程。
如果要编写便携式应用程序。

pthread_join()API

是一种等待线程终止的方便方法。
您可以编写自己的功能,该功能等待线程终止,也许更适合您的应用程序,而不是使用pthread_join()。
例如,它可以是基于等待条件变量的函数。

我建议阅读 David R. Butenhof的一本书“与Posix线程的编程”。
它很好地解释了讨论的主题(以及更复杂的事物)(尽管某些实现细节,例如主要功能中的pthread_exit用法,并不总是在书中反映出来)。

The pthread_exit() API

as has been already remarked, is used for the calling thread termination.
After a call to that function a complicating clean up mechanism is started.
When it completes the thread is terminated.
The pthread_exit() API is also called implicitly when a call to the return() routine occurs in a thread created by pthread_create().
Actually, a call to return() and a call to pthread_exit() have the same impact, being called from a thread created by pthread_create().

It is very important to distinguish the initial thread, implicitly created when the main() function starts, and threads created by pthread_create().
A call to the return() routine from the main() function implicitly invokes the exit() system call and the entire process terminates.
No thread clean up mechanism is started.
A call to the pthread_exit() from the main() function causes the clean up mechanism to start and when it finishes its work the initial thread terminates.

What happens to the entire process (and to other threads) when pthread_exit() is called from the main() function depends on the PTHREAD implementation.
For example, on IBM OS/400 implementation the entire process is terminated, including other threads, when pthread_exit() is called from the main() function.
Other systems may behave differently.
On most modern Linux machines a call to pthread_exit() from the initial thread does not terminate the entire process until all threads termination.
Be careful using pthread_exit() from main(), if you want to write a portable application.

The pthread_join() API

is a convenient way to wait for a thread termination.
You may write your own function that waits for a thread termination, perhaps more suitable to your application, instead of using pthread_join().
For example, it can be a function based on waiting on conditional variables.

I would recommend for reading a book of David R. Butenhof “Programming with POSIX Threads”.
It explains the discussed topics (and more complicated things) very well (although some implementation details, such as pthread_exit usage in the main function, not always reflected in the book).

又怨 2025-02-16 15:29:58

您不需要任何电话 pthread_exit(3)代码> 在您的特定代码中。

通常, main 线程应不是调用 pthread_exit ,但通常应调用 pthread_join(3) to 等待等待以完成其他一些线程。

在您的 printhello 函数中,您无需调用 pthread_exit ,因为它是在返回之后隐含的。

因此,您的代码应该是:

void *PrintHello(void *threadid)  {
  long tid = (long)threadid;
  printf("Hello World! It's me, thread #%ld!\n", tid);
  return threadid;
}

int main (int argc, char *argv[]) {
   pthread_t threads[NUM_THREADS];
   int rc;
   intptr_t t;
   // create all the threads
   for(t=0; t<NUM_THREADS; t++){
     printf("In main: creating thread %ld\n", (long) t);
     rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
     if (rc) { fprintf(stderr, "failed to create thread #%ld - %s\n",
                                (long)t, strerror(rc));
               exit(EXIT_FAILURE);
             };
   }
   pthread_yield(); // useful to give other threads more chance to run
   // join all the threads
   for(t=0; t<NUM_THREADS; t++){
      printf("In main: joining thread #%ld\n", (long) t);
      rc = pthread_join(&threads[t], NULL);
      if (rc) { fprintf(stderr, "failed to join thread #%ld - %s\n",
                                (long)t, strerror(rc));
               exit(EXIT_FAILURE);
      }
   }
}

You don't need any calls to pthread_exit(3) in your particular code.

In general, the main thread should not call pthread_exit, but should often call pthread_join(3) to wait for some other thread to finish.

In your PrintHello function, you don't need to call pthread_exit because it is implicit after returning from it.

So your code should rather be:

void *PrintHello(void *threadid)  {
  long tid = (long)threadid;
  printf("Hello World! It's me, thread #%ld!\n", tid);
  return threadid;
}

int main (int argc, char *argv[]) {
   pthread_t threads[NUM_THREADS];
   int rc;
   intptr_t t;
   // create all the threads
   for(t=0; t<NUM_THREADS; t++){
     printf("In main: creating thread %ld\n", (long) t);
     rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
     if (rc) { fprintf(stderr, "failed to create thread #%ld - %s\n",
                                (long)t, strerror(rc));
               exit(EXIT_FAILURE);
             };
   }
   pthread_yield(); // useful to give other threads more chance to run
   // join all the threads
   for(t=0; t<NUM_THREADS; t++){
      printf("In main: joining thread #%ld\n", (long) t);
      rc = pthread_join(&threads[t], NULL);
      if (rc) { fprintf(stderr, "failed to join thread #%ld - %s\n",
                                (long)t, strerror(rc));
               exit(EXIT_FAILURE);
      }
   }
}
别再吹冷风 2025-02-16 15:29:58

PTHREAD_EXIT()将终止调用线程并退出(但是,如果调用线程使用的资源不从主线程分离为操作系统。)

pthrade> pthrade_join()将等待或阻止调用线程,直到目标线程未终止。
简单地说,它将等待退出目标线程。

在您的代码中,如果将睡眠(或延迟)放入 printhello 函数之前 pthread_exit(),则可以退出主线程并终止完整过程,尽管您的> printhello 函数未完成,它将终止。如果您在呼叫 pthread_exit()之前使用 pthrade_join()函数,则从main中,它将阻止主线程并等待完成您的调用线程( printhello )。

pthread_exit() will terminate the calling thread and exit from that(but resources used by calling thread is not released to operating system if it is not detached from main thread.)

pthrade_join() will wait or block the calling thread until target thread is not terminated.
In simple word it will wait for to exit the target thread.

In your code, if you put sleep(or delay) in PrintHello function before pthread_exit(), then main thread may be exit and terminate full process, Although your PrintHello function is not completed it will terminate. If you use pthrade_join() function in main before calling pthread_exit() from main it will block main thread and wait to complete your calling thread (PrintHello).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文