【问题标题】:Thread doesn't recognize change in a flag线程无法识别标志的变化
【发布时间】:2016-06-08 22:01:02
【问题描述】:

我使用几个线程。只要将 exit_flag 设置为 false,所有程序都会运行。

我有特定的线程无法识别标志的变化,因此没有结束并释放其资源,我试图了解原因。

更新: 在用 gdb 调试了一下之后,我可以看到给定“足够的时间”,有问题的线程确实检测到了标志的变化。 我的结论是,没有足够的时间让线程检测到正常运行的变化。

我怎样才能'延迟'我的主线程,足够长的时间让所有线程都检测到标志的变化,而不必加入它们? (使用exit_flag 的目的是不加入线程,因为我不想为此管理所有线程ID - 我只是分离它们中的每一个,除了处理输入的线程)。 我试过在close_server()方法中使用sleep(5),在标志改变后,没有运气

注意事项:

  1. same 标志上循环的其他线程确实成功终止

  2. exit_flag 声明为:static volatile bool exit_flag

  3. 所有线程都在读取标志,标志值仅在我拥有的close_server() 方法中更改(仅此而已)

  4. 当线程在更改之前读取标志时可能发生的数据竞争对我来说并不重要,只要在 while 循环的下一次迭代中它会读取正确的值。

  5. 线程本身没有发生错误(根据 strerr 和 stdout,它们从错误消息中“干净”(对于我在线程中处理的错误)

  6. 即使注释掉整个 while((!exit_flag) && (remain_data > 0)) 代码块也会出现这种情况 - 所以这不是 sendfile 挂起的问题

station_info_t 结构:

typedef struct station_info {
    int socket_fd;
    int station_num;
} station_info_t;

有问题的线程代码:

void * station_handler(void * arg_p)
{
    status_type_t rs = SUCCESS;

    station_info_t * info = (station_info_t *)arg_p;
    int remain_data = 0;
    int sent_bytes = 0;
    int song_fd = 0;
    off_t offset = 0;
    FILE * fp = NULL;
    struct stat file_stat;

    /* validate station number for this handler */
    if(info->station_num < 0) {
        fprintf(stderr, "station_handler() station_num = %d, something's very wrong! exiting\n", info->station_num);
        exit(EXIT_FAILURE);
    }

    /* Open the file to send, and get his stats */
    fp = fopen(srv_params.songs_names[info->station_num], "r");

    if(NULL == fp) {
        close(info->socket_fd);
        free(info);
        error_and_exit("fopen() failed! errno = ", errno);
    }

    song_fd = fileno(fp);

    if( fstat(song_fd, &file_stat) ) {
        close(info->socket_fd);
        fclose(fp);
        free(info);
        error_and_exit("fstat() failed! errno = ", errno);
    }

    /** Run as long as no exit procedure was initiated */
    while( !exit_flag ) {
        offset = 0;
        remain_data = file_stat.st_size;

        while( (!exit_flag) && (remain_data > 0) ) {
            sent_bytes = sendfile(info->socket_fd, song_fd, &offset, SEND_BUF);
            if(sent_bytes < 0 ) {
                error_and_exit("sendfile() failed! errno = ", errno);
            }

            remain_data = remain_data - sent_bytes;
            usleep(USLEEP_TIME);
        }
    }

    printf("Station %d handle exited\n", info->station_num);

    /* Free \ close all resources */
    close(info->socket_fd);
    fclose(fp);
    free(info);
    return NULL;
}

我很乐意得到一些帮助。 谢谢大家

【问题讨论】:

  • 1) Yoda 条件不应该使用。 2)不要使用自制布尔类型/常量。 C 在stdbool.h 中提供了标准布尔类型和常量 3) 将布尔标志与常量进行比较是一个坏主意,因为它更难以阅读/理解。而是正确命名标志并对其进行测试。
  • 如果sendfile 挂起怎么办?您是否尝试过 strace/gdb 挂起的线程?
  • 一般来说,错误信息应该被发送到stderr,而不是stdout。所以建议将调用printf() 的错误消息替换为:fprintf( stderr, ....)
  • 当引用 errno 时,需要在调用设置 errno 变量的系统函数之后立即引用。不能保证close() 和/或fclose() 和/或free() 没有修改该值。建议去掉error_and_exit()函数,调用perror()然后清理,再调用exit(EXIT_FAILURE);
  • 为了保持一致,在所有子线程退出之前,主线程不能退出。一般来说,这意味着主线程在主线程退出之前为每个子线程ID调用pthread_join()

标签: c multithreading synchronization pthreads


【解决方案1】:

好吧,正如 user362924 所说,主要问题是我没有加入主线程中的线程,因此没有让它们有足够的时间退出。

如果由于某种原因不想加入所有线程并动态管理线程 ID,则解决此问题的方法是在主线程末尾使用 sleep 命令几秒钟。

当然,这种解决方法不是很好的做法,也不推荐(对任何通过 google 访问的人)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-10-21
    • 1970-01-01
    • 2016-01-19
    • 2011-11-06
    • 2014-07-11
    • 1970-01-01
    • 2015-08-16
    • 1970-01-01
    相关资源
    最近更新 更多