在线程之间共享文件句柄

时间:2015-12-12 21:29:14

标签: rust

我使用日志包进行一些基本的日志记录,我希望日志消息可以转到文件或stderr。我创建了一个结构来保存输出目标,但得到以下错误:

error: the trait `core::marker::Send` is not implemented for the type `std::io::Write + 'static` [E0277]
    impl log::Log for MyLogger {
        fn enabled(&self, metadata: &LogMetadata) -> bool {
        }

        fn log(&self, record: &LogRecord) {
        }
    ...
help: run `rustc --explain E0277` to see a detailed explanation
note: `std::io::Write + 'static` cannot be sent between threads safely
note: required because it appears within the type `Box<std::io::Write + 'static>`
note: required because it appears within the type `MyLogger`
note: required by `log::Log`

这是我用来测试这个代码的代码:

extern crate log;

use log::{LogRecord, LogMetadata, LogLevelFilter, SetLoggerError};
use std::io::{LineWriter, stderr, Write};
use std::fs::OpenOptions;
use std::sync::{Arc, Mutex};

struct MyLogger {
    out_stream: Arc<Mutex<Box<Write>>>
}

impl log::Log for MyLogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
    }

    fn log(&self, record: &LogRecord) {
    }
}

impl MyLogger {
    fn init(outfile: String) -> Result<(), SetLoggerError> {
        let logfile = match OpenOptions::new().create(true).append(true).open(&outfile) {
                Ok(f)  => Box::new(LineWriter::new(f)) as Box<Write>,
                Err(_) => Box::new(LineWriter::new(stderr())) as Box<Write>
            };

        log::set_logger(|max_log_level| {
            max_log_level.set(LogLevelFilter::Warn);
            Box::new(MyLogger{out_stream: logfile})         
        })
    }
}

fn main() {
    MyLogger::init("");
}

1 个答案:

答案 0 :(得分:2)

The Log traitSendSync的子广告:

pub trait Log: Sync + Send {
    fn enabled(&self, metadata: &LogMetadata) -> bool;
    fn log(&self, record: &LogRecord);
}

要为您自己的类型实施Log,您的类型也必须为SendSync

但是,您的MyLogger结构既不是Send也不是Sync,因为Box<Write>可能包含非Send类型。我们可以将该框限制为包含Send类型:

struct MyLogger {
    out_stream: Arc<Mutex<Box<Write + Send>>>
}

这足以使MyLogger SendSync成为extern crate log; use log::{LogRecord, LogMetadata, LogLevelFilter, SetLoggerError}; use std::io::{LineWriter, stderr, Write}; use std::fs::OpenOptions; use std::sync::{Arc, Mutex}; struct MyLogger { out_stream: Arc<Mutex<Box<Write + Send>>> } impl log::Log for MyLogger { fn enabled(&self, metadata: &LogMetadata) -> bool { unimplemented!() } fn log(&self, record: &LogRecord) { unimplemented!() } } impl MyLogger { fn init(outfile: &str) -> Result<(), SetLoggerError> { let logfile = match OpenOptions::new().create(true).append(true).open(outfile) { Ok(f) => Box::new(LineWriter::new(f)) as Box<Write + Send>, Err(_) => Box::new(LineWriter::new(stderr())) as Box<Write + Send> }; log::set_logger(|max_log_level| { max_log_level.set(LogLevelFilter::Warn); Box::new(MyLogger { out_stream: Arc::new(Mutex::new(logfile)) }) }) } } fn main() { MyLogger::init(""); } 。以下是您的代码,其中包含此修复程序和其他必要的修复程序:

 public static void Load_Image1(string name1, string name2, string name3,string LocationName)
{
    var startPath = Application.StartupPath;
    string Imagefolder = Path.Combine(startPath, "Image");
    string subImageFolder = Path.Combine(Imagefolder, LocationName);
    System.IO.Directory.CreateDirectory(subImageFolder);
    //string Jpeg = Path.Combine(Environment.CurrentDirectory, subImageFolder);

    List<PictureBox> pictureBoxes = new List<PictureBox>();
    pictureBoxes.Add(Image1);
    pictureBoxes.Add(Image2);
    pictureBoxes.Add(Image3);

    using (var wc = new System.Net.WebClient())
    {
        var uri = ("https://en.wikipedia.org/w/api.php?action=query&prop=imageinfo&format=json&iiprop=url&iiurlwidth=400&titles="+name1+"|"+name2+"|"+name3);
        var response = wc.DownloadString(new Uri(uri));
        var responseJson = JsonConvert.DeserializeObject<RootObject>(response);

        List<string> urls = new List<string>();
        foreach (KeyValuePair<string, Pageval> entry in responseJson.query.pages)
        {
            var url = entry.Value.imageinfo.First().thumburl;
            urls.Add(url);
            var hash = url.GetHashCode();
            string Jpeg = Path.Combine(Environment.CurrentDirectory, subImageFolder);
            var path = Path.Combine(Jpeg, hash.ToString("X") + ".jpg");
            wc.DownloadFile(url, path);

        }

        for (int i = 0; i < pictureBoxes.Count; i++)
        {
            Image1.SizeMode = PictureBoxSizeMode.StretchImage;
            Image2.SizeMode = PictureBoxSizeMode.StretchImage;
            Image3.SizeMode = PictureBoxSizeMode.StretchImage;
            pictureBoxes[i].Load(urls[i]);



          }

       }
    }
 }