@priority

Почему может падать программа с exit code: 0xc0000005, STATUS_ACCESS_VIOLATION?

Здравствуйте.

Я пытаюсь реализовать дессериализацию в объекты из большого json файла. Хочется сделать это как можно быстрее, поэтому я решил считывать файл по частям, закидывая эти части в вектор, а в другом потоке я использую считанные данные для дессериализации, тем самым уменьшая время простоя в ожидании завершения считывания из файла.

Более коротко: есть два потока, в одном потоке в цикле считывается файл кусками и кладется в вектор, в другом потоке этот вектор читается (.len(), обращение по индексу, ничего криминального) .

Проблема в том, что на больших файлах у меня выпадает ошибка STATUS_ACCESS_VIOLATION. Я понял, что выпадает она на моменте append'а одного вектора к другому. Моя гипотеза заключается в том, что, видимо, существует какой то race condition, хотя на первый взгляд, не должно.

main:
mod file_reader;
mod json_consumer;
mod specification;
mod frame;
mod pixel;

use file_reader::read_on_the_fly;
use std::thread;
use std::alloc::handle_alloc_error;
use std::time::{Duration, Instant};
use crate::json_consumer::{deserialize_on_the_fly};
use crate::frame::Frame;

fn main() {
    static mut CHAR_BUFFER: Vec<u8> = Vec::new();
    static mut FRAME_BUFFER: Vec<frame::Frame> = Vec::new();
    static mut IS_FILE_READ: bool = false;
    static mut SPECS: specification::Specification = specification::Specification { height: 0, width: 0, frames: 0 };

    let reader_handle = thread::spawn(|| unsafe {
        let start = Instant::now();
        let res = read_on_the_fly("file5_1160_786.json".to_string(), &mut CHAR_BUFFER, &mut IS_FILE_READ);
        if res.is_ok() {
            println!("\nFILE READ: done, elapsed time is {:?}",  start.elapsed().as_secs_f64());
        } else {
            println!("\nFILE READ: fail");
        }
    });

    let json_handle = thread::spawn(|| unsafe {
        let start = Instant::now();
        let res = deserialize_on_the_fly(&CHAR_BUFFER, &mut SPECS, &mut FRAME_BUFFER, &mut IS_FILE_READ);
        if res.is_ok() {
            println!("\nDESERIALIZE: done, elapsed time is {:?}",  start.elapsed().as_secs_f64());
        } else {
            println!("\nDESERIALIZE: fail");
        }
    });

    json_handle.join();
    reader_handle.join();
}


Вот тут я считываю:
use std::io;
use std::io::{Read, BufReader};
use std::fs::File;
use std::str;
use std::thread::sleep;
use std::time::Duration;

pub fn read_on_the_fly(path: String, buffer: &mut Vec<u8>, is_file_read: &mut bool) -> Result<(), io::Error> {
    static BUFF_SIZE: usize = 8192;
    let mut file = File::open(path)?;
    let mut br = BufReader::with_capacity(BUFF_SIZE, file);
    let mut tmp_buff = vec![0; BUFF_SIZE];

    while br.read(&mut tmp_buff)? != 0 {
        buffer.append(&mut tmp_buff.clone());
    }

    *is_file_read = true;
    Ok(())
}


Функция из второго потока довольно большая, но все, что происходит с общим вектором - это конструкции типа for i in 0..buff.len(), обращение по индексу и push(buff[i] as char) в другой вектор, может быть дело в этом?

Спасибо.
  • Вопрос задан
  • 43 просмотра
Пригласить эксперта
Ответы на вопрос 1
bingo347
@bingo347
Бородатый программер
Для начала стоит переписать все без unsafe (он здесь совсем не нужен)
Вместо некорректного шаринга уникальных ссылок IS_FILE_READ используйте AtomicBool
С CHAR_BUFFER тоже нарушили правило либо 1 mut/uniq borrow либо много shared borrow, заверните в Mutex, а лучше, учитывая однонаправленность данных передавайте через channel
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы