从线程停止main

时间:2019-02-03 23:22:54

标签: c pthreads valgrind

我一直在Raspberry pi上使用C进行修补,我的main()旋转了几个线程,其中一个线程中运行着一个小型Web服务器,

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

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

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== 

我了解到有种学问,当有东西砸到风扇上时,可以退出系统,然后允许操作系统进行清理。我试图用更快乐的valgrind使其退出/中止。我没有在此函数中执行任何显式的mallocs / callocs来在abort()之前调用free(),这引起了我的问题:

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

谢谢!

2 个答案:

答案 0 :(得分:1)

  

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

如果您希望整个程序停止运行,则可以调用_exit()-就是这样。

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

答案 1 :(得分:0)

我怀疑,如果成功创建了Web服务器并且线程正常退出,则不会发生内存泄漏,对吗?如果是这样,则主线程可能在退出之前有一些资源需要清理(似乎pthread_create会分配一些内存)。

因此,我建议您建立信号处理程序并适当终止主线程。函数abort()发送信号进行处理。因此,您可以创建信号处理程序以在主线程中捕获此类信号并进行清理。 Here是一个很好的例子。在示例中,SIGTERM被连接,原子变量done设置为1。在主循环中定期检查此变量,并且在终止1个程序的情况下。在终止之前,您可以停止Web服务器线程并释放在pthread_create中分配的内存。

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

其他想法:

  • 在主线程中使用pthread_join来监视Web服务器线程退出代码。在Web服务器线程中,调用pthread_exit以通知主线程错误并允许正常终止。考虑到,pthread_join将阻塞您的主线程。但是最好从main创建多个工作线程,然后一个一个地加入它们。

  • 使用Mutex / Conditional变量将错误通知主线程。 Web服务器线程将这种条件变量设置为某些错误代码,并以return退出。主线程将监视条件变量,并在发生错误的情况下终止程序。