从一个线程停止 main

stop main from a thread

我一直在用 C 在我的 Raspberry pi 上进行修补,我的 main() 启动了几个线程,其中一个线程中运行了一个小型网络服务器,

int main(){
        printf("hello world\n");
        thisfn();
        pthread_t tid, led_tid;
        int port = 9193;
        int rc = pthread_create(&tid, NULL, webserver, &port);
        assert (rc == 0);
/snip

如果网络服务器无法绑定到所需的端口,我希望整个程序停止。

void *webserver(void *vargp){
    int *port = (int *) vargp;
    printf("our port is %d\n", *port);

    /* First: Socket Creation */
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0){
            /* On error, -1 is returned */
            perror("Server Error!");
            abort();
    } else {
            printf("sockfd is %d\n", sockfd);
    }
    printf("Socket: sockfd: %d\n", sockfd);

    /* Second: Set socket options */
    int optval = 1;
    //int sockopt_int = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &optval, sizeof(optval) );
    int sockopt_int = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR , &optval, sizeof(optval) );
    if ( sockopt_int < 0 ){
            perror("Failed at setsockopt");
            abort();
    } else {
            printf("setsockopt succeeded\n");
    }

    /* Third: Bind to the port */
    /* int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); */
    struct sockaddr_in address;
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(*port);

    int bind_int = bind(sockfd, (struct sockaddr *)&address, sizeof(address)) ;
    printf("bind_int ; %d\n", bind_int);
    if (bind_int < 0 ) {
            perror("Failed at bind");
            abort(); 
    } else {
            printf("bind succeeded\n");
    }

我一直在调用 abort(),我也尝试过 exit(1)、_exit(1) 等 - 但是,当我使用 valgrind 检查时,这样做会泄漏内存(~136 字节)。

==13052== 136 bytes in 1 blocks are possibly lost in loss record 1 of 1
==13052==    at 0x4849CE0: calloc (vg_replace_malloc.c:711)
==13052==    by 0x401379B: allocate_dtv (dl-tls.c:322)
==13052==    by 0x40141D3: _dl_allocate_tls (dl-tls.c:539)
==13052==    by 0x489D9EF: allocate_stack (allocatestack.c:580)
==13052==    by 0x489D9EF: pthread_create@@GLIBC_2.4 (pthread_create.c:539)
==13052==    by 0x10EBF: main (fixmem.c:38)
==13052== 
==13052== LEAK SUMMARY:
==13052==    definitely lost: 0 bytes in 0 blocks
==13052==    indirectly lost: 0 bytes in 0 blocks
==13052==      possibly lost: 136 bytes in 1 blocks
==13052==    still reachable: 0 bytes in 0 blocks
==13052==         suppressed: 0 bytes in 0 blocks
==13052== 

我了解到一种思想流派,当遇到问题时,可以退出,然后让 OS 进行清理。我试图用更快乐的 valgrind 使它成为 exit/abort。我没有在这个函数中做任何明确的 mallocs/callocs 来在 abort() 之前调用 free() - 这引出了我的问题:

从线程停止 main 并退出的最干净的方法是什么?

谢谢!

我怀疑,如果webserver创建成功,线程正常退出,应该不会有内存泄漏吧?如果是这样,主线程在退出之前可能有一些资源需要清理(似乎 pthread_create 分配了一些内存)。

所以我可能会建议建立信号处理程序并优雅地终止主线程。函数 abort() 向进程发送信号。因此,您可以创建信号处理程序以在主线程中捕获此类信号并进行清理。 Here 是如何做到这一点的好例子。在示例中,SIGTERM 被缓存,原子变量 done 被设置为 1。这个变量在主循环中定期检查,如果有 1 个程序终止。在此类终止之前,您可以停止网络服务器线程并释放在 pthread_create.

中分配的内存

abort() 发送 SIGABRT,因此您必须更改示例中的代码)

其他想法:

  • 使用pthread_join from main thread to monitor webserver thread exit code. In webserver thread call pthread_exit通知主线程错误并允许正常终止。请注意,pthread_join 会阻塞您的主线程。但是从 main 创建几个工作线程并一个接一个地加入它们可能是个好主意。

  • 使用 Mutex/Conditional 变量通知主线程有关错误。 Web 服务器线程将此类条件变量设置为某个错误代码并以 return 退出。主线程将监视条件变量,并在出现错误时终止程序。

If the webserver is unable to bind to the desired port, I want the entire program to stop.

如果您希望整个程序停止,调用 _exit() 完全没问题 - 这就是它的用途。

忽略 valgrind 报告的 "leaks",它们是由于清理代码没有机会 运行 而造成的误报。由于 OS 回收属于已退出进程的所有内存(和其他资源),因此实际上没有内存泄漏。