2009-01-18 15 views
11

Seri bağlantı noktasındaki bir aygıttan okuma ve yazma için boost :: asio kullanmaya çalışıyorum. Okunacak herhangi bir şey olmadığında, hem boost :: asio: read() ve boost :: asio :: serial_port :: read_some() bloğu. Bunun yerine, bu durumu tespit etmek ve cihazı tekmelemek için bağlantı noktasına bir komut yazmak istiyorum.Asio'yu kullanarak okunmayan bir okuma nasıl yapılır?

nasıl ya hiç veriler olduğunu algılayabilir? Ben uyumsuz her şeyi yapabilirsiniz

Gerekirse eğer yapabilirsem, sadece ziyade ekstra karmaşıklığı önlemek olacaktır.

cevap

17

Aslında birkaç seçeneğiniz var. Sen seri bağlantı noktasının yerleşik async_read_some işlevini kullanabilirsiniz veya takvimi tek başına işlev boost::asio::async_read (veya async_read_some) kullanabilir.

(1) veri okumak veya (2) bir hata oluşursa sürece bunların hiçbiri geri arama arayacak beri Hala etkili olan durum "bloke" içine edeceğiz. Bunu aşmak için, bir zaman aşımı ayarlamak üzere deadline_timer nesnesini kullanmak istersiniz. Zaman aşımı önce patlarsa, veri mevcut değildi. Aksi takdirde, okumanız olacak.

Eklenen karmaşıklık gerçekten de o kadar da kötü değil. Benzer davranışa sahip iki geri arama ile sonuçlanacaksınız. "Okumak" veya "zaman aşımı" geri çağırma bir hata ile ateş ederse, bunun yarış kaybeden olduğunu bilirsiniz. Eğer biri hata yapmadan ateş ederse, o zaman yarış kazananı olduğunu bilirsiniz (ve diğer aramayı iptal etmelisiniz). read_some numaralı telefona engelleme yaptığınız yerde, şimdi io_svc.run() numaralı telefonu arayacaksınız. İşleviniz, run numaralı telefonu çağırdığında olduğu gibi engellenir, ancak bu kez süreyi denetlersiniz. Eğer belirli ihtiyaçlarını karşılamak için orada burada sadece birkaç tweaks ile başlamak gerekir

void foo() 
{ 
    io_service  io_svc; 
    serial_port ser_port(io_svc, "your string here"); 
    deadline_timer timeout(io_svc); 
    unsigned char my_buffer[1]; 
    bool   data_available = false; 

    ser_port.async_read_some(boost::asio::buffer(my_buffer), 
     boost::bind(&read_callback, boost::ref(data_available), boost::ref(timeout), 
        boost::asio::placeholders::error, 
        boost::asio::placeholders::bytes_transferred)); 
    timeout.expires_from_now(boost::posix_time::milliseconds(<<your_timeout_here>>)); 
    timeout.async_wait(boost::bind(&wait_callback, boost::ref(ser_port), 
        boost::asio::placeholders::error)); 

    io_svc.run(); // will block until async callbacks are finished 

    if (!data_available) 
    { 
    kick_start_the_device(); 
    } 
} 

void read_callback(bool& data_available, deadline_timer& timeout, const boost::system::error_code& error, std::size_t bytes_transferred) 
{ 
    if (error || !bytes_transferred) 
    { 
    // No data was read! 
    data_available = false; 
    return; 
    } 

    timeout.cancel(); // will cause wait_callback to fire with an error 
    data_available = true; 
} 

void wait_callback(serial_port& ser_port, const boost::system::error_code& error) 
{ 
    if (error) 
    { 
    // Data was read and this timeout was canceled 
    return; 
    } 

    ser_port.cancel(); // will cause read_callback to fire with an error 
} 

:

İşte bir örnek. Umarım bu yardımcı olur!

başka not: İlave ipler geri aramalar işlemek için gerekliydi. Her şey run() numaralı çağrı ile ele alınır. ... Zaten bunun farkında olsaydı emin değil

+0

Bu yaklaşımı kullandım ve iyi çalışıyor, ancak yalnızca ilk kez. Bir sonraki io_svc.run() çağrısı hemen döner. Fazladan bir şey yapmam gerekecek mi? Teşekkür – Schiavini

+3

görünüşte io_svc.run() sonra io_svc.reset() aramak zorunda kaldı. – Schiavini

+0

büyük cevap, çok yararlı. Ancak, bazı garip davranışlar alıyorum: Seri portuna her 5 ms'de bir veri yazma ve başka bir okuma dizisinden veri yazma programım var, ancak eğer okuyucunun gecikme süresini 5 ms'ye ayarladıysam, hala "veri kullanılamıyor" oluyor okunan değerler ile karışık aramalar.Bu, koddaki bazı ek yüklerden mi kaynaklanıyor yoksa bir şeyleri mi özlüyorum? – joaocandre

1

Sen asio serbest fonksiyonunu kullanmak zorunda :: async_read.

1

Onun aslında burada çok yanıtlardan daha basit ima ettiniz ve eşzamanlı yapabilirsiniz:

:

Engelleme okuma böyle bir şey oldu varsayalım

size_t len = socket.receive_from(boost::asio::buffer(recv_buf), sender_endpoint); 

Sonra neredeyse tüm gönderme/yöntem var almak receive_from alternatif aşırı formu kullanarak

socket.non_blocking(true); 
size_t len = 0; 
error = boost::asio::error::would_block; 
while (error == boost::asio::error::would_block) 
    //do other things here like go and make coffee 
    len = socket.receive_from(boost::asio::buffer(recv_buf), sender_endpoint, 0, error); 
std::cout.write(recv_buf.data(), len); 

ile değiştirin. Ne yazık ki bayrak argümanı aldılar ama 0 iyi çalışıyor gibi görünüyor.

+0

Örneğiniz soru, seri bağlantı noktasıyla ilgili iken, soket örneğini kapsar. –