C程序中的多线程

5

我正在使用C语言编写一个Unix应用程序,该程序使用多个线程。我遇到了一个问题,主函数在生成的线程完成工作之前就终止了。我该如何防止这种情况发生?我怀疑我需要使用pthread_join原语,但是我不确定如何使用。谢谢!


3
尝试发布错误信息,将会得到更好的反馈。 - senfo
5个回答

8

是的,你可以使用pthread_join()(请参见其他答案如何实现)。但让我解释一下pthread模型并向您展示另一个选项。

在Unix中,当主线程从main返回、任何线程调用exit()或最后一个线程调用pthread_exit()时,进程将退出。基于最后一个选项,您可以简单地让您的主线程调用pthread_exit(),只要还有至少一个线程正在运行,进程便会保持活动状态。


5
是的,其中一种方法是使用pthread_join函数:假设您的线程处于“可链接”状态。
  • pthread_create:此函数返回控制权后,您的线程将执行线程函数。

  • pthread_create之后,使用来自pthread_create的tid调用pthread__join

如果您的线程已分离,则必须使用其他技术,例如共享变量,在信号上等待,共享队列等。
这里提供了很好的参考资料:这里

2
只有点踩,却没有评论...你难道不喜欢这样吗...当然不喜欢! - jldupont
1
共享变量、信号或队列会使事情变得不必要的复杂。只需从main()调用pthread_exit()并完成它。 - Dan Moulding
2
@dan:我猜这很大程度上取决于你一开始想要做什么。仅仅因为你在某些场合使用了某项技术并不意味着它就是最好的工具。如果你因此而对我进行了反对票(但我相信你没有),那么你可能需要重新考虑一下。 - jldupont
1
@jldupont:对于一个给定的问题,我更喜欢一个简单的解决方案来解决这个问题,而不是一个不必要复杂的解决方案。无论你试图做什么,选择简单的解决方案都是一种很好的工程感觉。几乎从来没有一个情况是不必要复杂的解决方案比简单的解决方案更好。pthread_exit 函数几乎总是 OP 所提出的问题的最简单解决方案。我对你的回答进行了负面评价,因为它只是建议了其他不必要复杂的解决方案。请不要把它当作个人攻击。 - Dan Moulding
1
@dan:我同意最简单的解决方案,但在分离线程的情况下,你必须在退出线程之前有某种信息。假设线程知道它可以安全地退出,那么你就不需要额外的开销。无论如何,我已经结束了这个争论。 - jldupont

3

有许多不同的方法可以做到这一点,但最简单的方法是在从 main() 返回之前调用pthread_exit()

请注意,即使您想要等待的线程不可连接,这种技术也可以实现。


我不熟悉pthread,但在Unix中,如果主线程退出时仍有子线程运行,这可能会导致进程无法正确响应针对该进程的信号。请注意,我说的是Unix。我的*nix培训已经接近20年了。(哎呀。) - jmucchiello
理论上,所有的线程都可以处理信号,但实际上哪个线程会处理信号是不确定的。这种理论是否在实践中得以实现可能还有待商榷。 - Jonathan Leffler
根据我所了解的,pthread最早是在1997年的SUSv2中指定的。因此,听起来你的Unix培训可能早于pthread,所以你当时使用的内容可能与现代Unix没有任何关系。无论如何,我可以告诉你,我的POSIX培训,虽然不到20年,但教给我信号在主线程退出后仍然可以被捕获,没有任何问题 ;) - Dan Moulding
@jmucchiello:有关pthreads规范的第一次出版更正:它至少可以追溯到1995年。当时它被称为IEEE 1003.1c,显然早于SUSv2。 - Dan Moulding
+1. pthread_exitmain() 线程中退出是一种简单但相对较为不知名的技术。 (我看过的大多数关于 pthread_exit 的参考文献更多地告诉读者有关 pthreads 上下文中的 exit(3) 而非此函数。) - pilcrow

1

看看我为我的一个库编写的这个简单的C代码

/*
 *   Copyright (c) 2011 Dino Ciuffetti <dino@tuxweb.it>, TuxWeb S.r.l., NuvolaBase Ltd
 *   
 *   This file is part of liborient.
 *
 *   Liborient is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   Liborient is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public License
 *   along with Liborient.  If not, see <http://www.gnu.org/licenses/>.
*/

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

//pthread_rwlock_t ptr_thr_lock = PTHREAD_RWLOCK_INITIALIZER;

typedef struct {
        int t;
} thread_arguments;

void *thread_stuff(void *args) {
        thread_arguments *t_args;
        int tid;

        t_args = (thread_arguments *)args;
        //pthread_rwlock_rdlock(&ptr_thr_lock);
        tid = t_args->t;
        //pthread_rwlock_unlock(&ptr_thr_lock);

        /*while (1) {
        sleep (1);*/
        printf("Thread #%i!\n", tid);
        /*}*/

        t_args = NULL;
        pthread_exit(NULL);
        return NULL;
}

int wait_threads(pthread_t threads[], thread_arguments *t_args[], int nthreads) {
        int t;
        int rc;

        // Waiting for threads termination
        for(t=0; t<nthreads; t++) {
                rc = pthread_join(threads[t], NULL);
                free(t_args[t]);
                if (rc != 0) {
                        printf("Error waiting for termination of thread %i: %i\n", t, rc);
                        return 1;
                        break;
                }
        }

        return 0;
}

int spawn_threads(pthread_t threads[], thread_arguments *t_args[], int nthreads) {
        int t;
        int rc;

        // Spawning threads
        for(t=0; t<nthreads; t++) {
                t_args[t] = (thread_arguments *) malloc(sizeof(thread_arguments));
                //pthread_rwlock_wrlock(&ptr_thr_lock);
                t_args[t]->t = t;
                //pthread_rwlock_unlock(&ptr_thr_lock);

                printf("Spawning thread: %i\n", t);
                rc = pthread_create(&threads[t], NULL, (void *)thread_stuff, (void *)t_args[t]);
                if (rc != 0) {
                        printf("Error spawning thread %i: %i\n", t, rc);
                        wait_threads(threads, t_args, rc+1);
                        return t+1;
                        break;
                }
        }

        return 0;
}

int main() {
        pthread_t threads[20];
        thread_arguments *t_args[20];
        int rc;

        rc = spawn_threads(threads, t_args, 20);
        if (rc > 0) {
                printf("Failed spawning thread number %i\n", rc-1);
                return 1;
        }

        rc = wait_threads(threads, t_args, 20);

        return 0;
}

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接