2013-02-22 43 views
8

Tôi có chủ đề OpenMP ghi vào bàn điều khiển qua cout và cerr. Điều này tất nhiên là không an toàn, vì đầu ra có thể được xen kẽ. Tôi có thể làm một cái gì đó giống nhưnhiều chủ đề viết tới std :: cout hoặc std :: cerr

#pragma omp critical(cerr) 
{ 
    cerr << "my variable: " << variable << endl; 
} 

Nó sẽ đẹp hơn nếu có thể thay thế cerr với một phiên bản thread-safe, tương tự như cách tiếp cận giải thích trong cuốn hướng dẫn valgrind DRD (http://valgrind.org/docs/manual/drd-manual.html#drd-manual.effective-use) trong đó bao gồm phát sinh một lớp từ std :: ostreambuf . Lý tưởng nhất là cuối cùng tôi sẽ chỉ thay thế cerr bằng cerr có chuỗi của riêng tôi, ví dụ: chỉ cần:

tcerr << "my variable: " << variable << endl; 

Lớp học như vậy có thể in ra bàn điều khiển ngay sau khi nó gặp "lỗi". Tôi không quan tâm nếu các dòng từ các chủ đề khác nhau được xen kẽ, nhưng mỗi dòng sẽ chỉ xuất phát từ một chuỗi.

Tôi không thực sự hiểu cách tất cả luồng này trong C++ hoạt động, nó quá phức tạp. Có ai như một lớp học hoặc có thể chỉ cho tôi làm thế nào để tạo ra một lớp học như vậy cho mục đích đó?

+0

xin đừng đề nghị printf ..;) – Wolfgang

+0

* "Điều này tất nhiên không phải là an toàn" * - Điều này không đúng trong C++ 11, trừ khi bạn hành động có chủ ý để làm cho nó thật . –

+0

Tiêu đề của bạn nói 'cout' không phải là' cerr'. – Barmar

Trả lời

0

Bạn có thể làm điều đó bằng cách kế thừa std::basic_streambuf và ghi đè các hàm chính xác để đảm bảo an toàn. Sau đó, sử dụng lớp này cho các đối tượng luồng của bạn.

8

Bạn có thể sử dụng cách tiếp cận tương tự như trình tạo chuỗi. Tạo một tổ chức phi mẫu lớp rằng:

  • cung cấp templated operator<< để chèn vào đối tượng này
  • nội bộ được xây dựng thành một std::ostringstream
  • bãi các nội dung về tiêu hủy

cách tiếp cận Rough:

class AtomicWriter { 
    std::ostringstream st; 
public: 
    template <typename T> 
    AtomicWriter& operator<<(T const& t) { 
     st << t; 
     return *this; 
    } 
    ~AtomicWriter() { 
     std::string s = st.str(); 
     std::cerr << s; 
     //fprintf(stderr,"%s", s.c_str()); 
     // write(2,s.c_str(),s.size()); 
    } 
}; 

Sử dụng làm:

0 hơn
AtomicWriter() << "my variable: " << variable << "\n"; 

Hoặc trong tình huống phức tạp:

{ 
    AtomicWriter w; 
    w << "my variables:"; 
    for (auto & v : vars) { 
     w << ' ' << v; 
    } 
} // now it dumps 

Bạn sẽ cần phải bổ sung thêm quá tải nếu bạn muốn thao tác, bạn có thể sử dụng write tốt hơn so với fprintf cho nguyên tử ghi trong destructor, hoặc std::cerr , bạn có thể khái quát để đích được chuyển đến hàm tạo (std::ostream/mô tả tệp/FILE*),

+0

Tôi nghĩ rằng tôi cũng sẽ thêm một thành viên 'flush' làm giống như destructor và xóa bộ đệm bên trong. Sau đó, bạn có thể tái sử dụng cùng một nguyên tử hơn và hơn nếu bạn muốn. Một số người có thể thích sử dụng thêm phạm vi như trong ví dụ thứ hai của bạn. –

+0

@MooingDuck: Không chắc chắn cách đi ... Tôi hiểu những gì bạn yêu cầu, nhưng tôi thấy rằng phạm vi cho phép tôi bỏ qua các nội dung khi tôi nhìn vào logic chứ không phải dấu vết (khung đăng nhập của chúng tôi cho phép tương tự cấu trúc). Tức là, khi được sử dụng đúng (nghĩa là không trộn logic với ghi nhật ký), phạm vi có thể được sử dụng để phân tích nội dung và đảm bảo rằng không có logic thực ở đó, sau đó tôi không cần phải giải thích những vòng lặp nội bộ đang làm nếu tôi nhìn vào logic của toàn bộ hàm. –

20

Như những người khác đã chỉ ra, trong C++ 11, std::cout chỉ an toàn.

Tuy nhiên nếu bạn sử dụng nó như

std::cout << 1 << 2 << 3; 

với chủ đề khác nhau, sản lượng vẫn có thể được xen kẽ, vì mỗi << là một cuộc gọi chức năng mới có thể được preceeded bởi bất kỳ cuộc gọi chức năng trên thread khác.

Để tránh đan xen mà không một #pragma omp critical - mà có thể khóa tất cả mọi thứ - bạn có thể làm như sau:

std::stringstream stream; // #include <sstream> for this 
stream << 1 << 2 << 3; 
std::cout << stream.str(); 

Ba cuộc gọi viết 123 vào dòng đang xảy ra chỉ trong một thread để một địa phương, phi đối tượng chia sẻ, do đó không bị ảnh hưởng bởi bất kỳ chủ đề nào khác. Sau đó, chỉ có một cuộc gọi đến luồng đầu ra được chia sẻ std::cout, khi thứ tự của các mục 123 đã được sửa, do đó sẽ không bị rối tung lên.

0

Tôi không có đủ danh tiếng để đăng nhận xét, nhưng tôi muốn đăng thêm vào lớp AtomicWriter để hỗ trợ std :: endl và cho phép các luồng khác được sử dụng ngoài std :: cout. Ở đây là:

class AtomicWriter { 
    std::ostringstream st; 
    std::ostream &stream; 
public: 
    AtomicWriter(std::ostream &s=std::cout):stream(s) { } 
    template <typename T> 
    AtomicWriter& operator<<(T const& t) { 
     st << t; 
     return *this; 
    } 
    AtomicWriter& operator<<(std::ostream&(*f)(std::ostream&)) { 
     st << f; 
     return *this; 
    } 
    ~AtomicWriter() { stream << st.str(); } 
}; 
Các vấn đề liên quan