2012-09-13 10 views
12

Điều tôi muốn làm là tạo một loại "ống" (giống như một đường ống giữa các quy trình), nhưng giữa C++ iostreams trong cùng một chương trình. Tôi có một hàm yêu cầu luồng đầu vào làm đối số, nhưng dữ liệu của tôi đến từ luồng đầu ra. Vì vậy, có một cách tiêu chuẩn để ống đầu ra của một std::ostream vào đầu vào của một std::istream?C++ kết nối luồng đầu ra với luồng đầu vào

+2

Có std :: stringstream phù hợp với nhu cầu của bạn không? Nếu không, hãy giải thích lý do. – AProgrammer

+1

Có một iostream (thông báo nó có 'i' và' o' ngay từ đầu). Bạn bơm dữ liệu trong một đầu và nó đi ra có kết thúc. Đó là điều bạn muốn. –

+0

-1 câu hỏi chưa được xác định. –

Trả lời

13

Bạn có thể tạo std::streambuf nơi đầu ra đi tới một bộ đệm và std::overflow() khối khi bộ đệm đầy. Ở đầu bên kia, bạn sẽ có một bộ đệm đầu vào chặn trên underflow() khi bộ đệm trống. Rõ ràng, đọc và viết sẽ có hai chủ đề khác nhau.

Doanh nghiệp khó khăn là cách đồng bộ hóa hai bộ đệm: Các luồng không sử dụng bất kỳ thao tác đồng bộ hóa nào khi truy cập bộ đệm. Chỉ khi bất kỳ chức năng ảo nào được gọi, bạn có thể chặn hoạt động và xử lý đồng bộ hóa. Mặt khác, không sử dụng một bộ đệm là khá kém hiệu quả. Cách tôi giải quyết vấn đề này là sử dụng bộ đệm đầu ra tương đối nhỏ (ví dụ: 256 char s) và cũng ghi đè sync() để sử dụng chức năng này để chuyển các ký tự vào bộ đệm đầu vào. streambuf sẽ sử dụng mutex cho đồng bộ hóa và biến điều kiện để chặn trên bộ đệm đầu vào đầy đủ trên đầu ra và bộ đệm đầu vào trống trên đầu vào. Để hỗ trợ tắt máy sạch sẽ cũng có một chức năng thiết lập một lá cờ mà không có đầu vào nhiều hơn là đến và tất cả các hoạt động đầu ra hơn nữa nên thất bại.

Tạo triển khai thực tế cho thấy hai bộ đệm không đủ: các chuỗi truy cập đầu vào và bộ đệm đầu ra có thể hoạt động khi các khối đệm khác tương ứng. Do đó, một bộ đệm trung gian thứ ba là cần thiết. Với sự thay đổi nhỏ so với kế hoạch trên, dưới đây là một số mã (nó sử dụng các bộ đệm nhỏ để đảm bảo có các luồng tràn và dòng dưới thực tế; vì ít nhất bộ đệm đầu vào có thể lớn hơn).

// threadbuf.cpp              -*-C++-*- 
// ---------------------------------------------------------------------------- 
// Copyright (C) 2013 Dietmar Kuehl http://www.dietmar-kuehl.de   
//                  
// Permission is hereby granted, free of charge, to any person   
// obtaining a copy of this software and associated documentation  
// files (the "Software"), to deal in the Software without restriction, 
// including without limitation the rights to use, copy, modify,   
// merge, publish, distribute, sublicense, and/or sell copies of   
// the Software, and to permit persons to whom the Software is   
// furnished to do so, subject to the following conditions:    
//                  
// The above copyright notice and this permission notice shall be  
// included in all copies or substantial portions of the Software.  
//                  
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,  
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES  
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND    
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT   
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,   
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING   
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR   
// OTHER DEALINGS IN THE SOFTWARE. 
// ---------------------------------------------------------------------------- 


#include <algorithm> 
#include <condition_variable> 
#include <iostream> 
#include <mutex> 
#include <stdexcept> 
#include <streambuf> 
#include <string> 
#include <thread> 

// ---------------------------------------------------------------------------- 

class threadbuf 
    : public std::streambuf 
{ 
private: 
    typedef std::streambuf::traits_type traits_type; 
    typedef std::string::size_type  string_size_t; 

    std::mutex    d_mutex; 
    std::condition_variable d_condition; 
    std::string    d_out; 
    std::string    d_in; 
    std::string    d_tmp; 
    char*     d_current; 
    bool     d_closed; 

public: 
    threadbuf(string_size_t out_size = 16, string_size_t in_size = 64) 
     : d_out(std::max(string_size_t(1), out_size), ' ') 
     , d_in(std::max(string_size_t(1), in_size), ' ') 
     , d_tmp(std::max(string_size_t(1), in_size), ' ') 
     , d_current(&this->d_tmp[0]) 
     , d_closed(false) 
    { 
     this->setp(&this->d_out[0], &this->d_out[0] + this->d_out.size() - 1); 
     this->setg(&this->d_in[0], &this->d_in[0], &this->d_in[0]); 
    } 
    void close() 
    { 
     { 
      std::unique_lock<std::mutex> lock(this->d_mutex); 
      this->d_closed = true; 
      while (this->pbase() != this->pptr()) { 
       this->internal_sync(lock); 
      } 
     } 
     this->d_condition.notify_all(); 
    } 

private: 
    int_type underflow() 
    { 
     if (this->gptr() == this->egptr()) 
     { 
      std::unique_lock<std::mutex> lock(this->d_mutex); 
      while (&this->d_tmp[0] == this->d_current && !this->d_closed) { 
       this->d_condition.wait(lock); 
      } 
      if (&this->d_tmp[0] != this->d_current) { 
       std::streamsize size(this->d_current - &this->d_tmp[0]); 
       traits_type::copy(this->eback(), &this->d_tmp[0], 
            this->d_current - &this->d_tmp[0]); 
       this->setg(this->eback(), this->eback(), this->eback() + size); 
       this->d_current = &this->d_tmp[0]; 
       this->d_condition.notify_one(); 
      } 
     } 
     return this->gptr() == this->egptr() 
      ? traits_type::eof() 
      : traits_type::to_int_type(*this->gptr()); 
    } 
    int_type overflow(int_type c) 
    { 
     std::unique_lock<std::mutex> lock(this->d_mutex); 
     if (!traits_type::eq_int_type(c, traits_type::eof())) { 
      *this->pptr() = traits_type::to_char_type(c); 
      this->pbump(1); 
     } 
     return this->internal_sync(lock) 
      ? traits_type::eof() 
      : traits_type::not_eof(c); 
    } 
    int sync() 
    { 
     std::unique_lock<std::mutex> lock(this->d_mutex); 
     return this->internal_sync(lock); 
    } 
    int internal_sync(std::unique_lock<std::mutex>& lock) 
    { 
     char* end(&this->d_tmp[0] + this->d_tmp.size()); 
     while (this->d_current == end && !this->d_closed) { 
      this->d_condition.wait(lock); 
     } 
     if (this->d_current != end) 
     { 
      std::streamsize size(std::min(end - d_current, 
              this->pptr() - this->pbase())); 
      traits_type::copy(d_current, this->pbase(), size); 
      this->d_current += size; 
      std::streamsize remain((this->pptr() - this->pbase()) - size); 
      traits_type::move(this->pbase(), this->pptr(), remain); 
      this->setp(this->pbase(), this->epptr()); 
      this->pbump(remain); 
      this->d_condition.notify_one(); 
      return 0; 
     } 
     return traits_type::eof(); 
    } 
}; 

// ---------------------------------------------------------------------------- 

static void writer(std::ostream& out) 
{ 
    for (std::string line; std::getline(std::cin, line);) 
    { 
     out << "writer: '" << line << "'\n"; 
    } 
} 

// ---------------------------------------------------------------------------- 

static void reader(std::istream& in) 
{ 
    for (std::string line; std::getline(in, line);) 
    { 
     std::cout << "reader: '" << line << "'\n"; 
    } 
} 

// ---------------------------------------------------------------------------- 

int main() 
{ 
    try 
    { 
     threadbuf sbuf; 
     std::ostream out(&sbuf); 
     std::istream in(&sbuf); 

     std::thread write(&::writer, std::ref(out)); 
     std::thread read(&::reader, std::ref(in)); 

     write.join(); 
     sbuf.close(); 
     read.join(); 
    } 
    catch (std::exception const& ex) 
    { 
     std::cerr << "ERROR: " << ex.what() << "\n"; 
    } 
} 
+1

+1 cho nỗ lực; OP chắc chắn đang tìm kiếm một bản sửa lỗi nhanh chóng và dễ dàng hơn nhiều. – Walter

+0

Vâng, sử dụng mã ở trên ** là ** nhanh cho snybody nhưng tôi :) Tôi đã thấy yêu cầu tương tự trước đây, tức là, nó có thể hữu ích cho những người khác, quá. ... và đó là một bài tập thú vị để thực sự triển khai những gì tôi chỉ vạch ra trước đây. Cuối cùng: Tôi không biết một sửa chữa dễ dàng hơn! –

+0

Bạn là một huyền thoại Flipping Dietmar. Tôi đang sử dụng điều này trong một bài kiểm tra đơn vị và nó hoạt động một điều trị. Cảm ơn. – MattSmith