2009-05-05 34 views
10

Nền tảng của tôi là windows vista 32, với hình ảnh C++ express 2008.Nhiều chủ đề đọc từ cùng một tập tin

ví dụ:

nếu tôi có tệp chứa 4000 byte, tôi có thể đọc 4 chuỗi từ cùng một lúc không? và mỗi luồng truy cập một phần khác của tệp.

chủ đề 1 đọc 0-999, chủ đề 2 đọc 1000 - 2999, v.v.

vui lòng cung cấp ví dụ bằng ngôn ngữ C.

+1

Nghe như bài tập về nhà. Bạn sử dụng thư viện luồng nào? Bạn bị kẹt ở đâu? – dirkgently

+0

không phải là một bài tập về nhà, dude, tôi chỉ muốn biết nếu nó có thể hay không. Tôi thậm chí không biết cách làm, vì hầu hết giải pháp được đăng trên google không giống như tệp truy cập song song đúng, tất cả đều sử dụng khóa – anru

Trả lời

20

Nếu bạn không viết thư cho họ, không cần phải chăm sóc điều kiện đồng bộ/chủng tộc.

Chỉ cần mở tệp có tính năng đọc được chia sẻ dưới dạng các tay cầm khác nhau và mọi thứ sẽ hoạt động. (nghĩa là, bạn phải mở tệp trong ngữ cảnh của chuỗi thay vì chia sẻ cùng một tệp xử lý).

#include <stdio.h> 
#include <windows.h> 

DWORD WINAPI mythread(LPVOID param) 
{ 
    int i = (int) param; 
    BYTE buf[1000]; 
    DWORD numread; 

    HANDLE h = CreateFile("c:\\test.txt", GENERIC_READ, FILE_SHARE_READ, 
     NULL, OPEN_EXISTING, 0, NULL); 

    SetFilePointer(h, i * 1000, NULL, FILE_BEGIN); 
    ReadFile(h, buf, sizeof(buf), &numread, NULL); 
    printf("buf[%d]: %02X %02X %02X\n", i+1, buf[0], buf[1], buf[2]); 

    return 0; 
} 

int main() 
{ 
    int i; 
    HANDLE h[4]; 

    for (i = 0; i < 4; i++) 
     h[i] = CreateThread(NULL, 0, mythread, (LPVOID)i, 0, NULL); 

    // for (i = 0; i < 4; i++) WaitForSingleObject(h[i], INFINITE); 
    WaitForMultipleObjects(4, h, TRUE, INFINITE); 

    return 0; 
} 
+1

Vòng lặp với WaitForSingleObject() nên được thay thế bằng một cuộc gọi WaitForMultipleObjects() duy nhất. Khác hơn là +1. – mghie

2

Bạn chắc chắn có thể đọc nhiều chủ đề từ cấu trúc dữ liệu, điều kiện chủng tộc có thể xảy ra nếu bất kỳ viết nào đang diễn ra.

Để tránh các điều kiện chủng tộc như vậy, bạn cần phải xác định ranh giới mà chủ đề có thể đọc, nếu bạn có một số lượng rõ ràng của các phân đoạn dữ liệu và một số lượng rõ ràng của các chủ đề để phù hợp với những điều đó thì dễ dàng.

Ví dụ trong C, bạn sẽ cần phải cung cấp thêm một số thông tin, như thư viện luồng mà bạn đang sử dụng. Hãy thử trước, sau đó chúng tôi có thể giúp bạn khắc phục bất kỳ vấn đề nào.

+0

tôi chưa viết chương trình, nhưng tôi sẽ thử pthread, vì tôi đã làm một số pthread công việc trong Linux. chương trình sẽ không viết bất cứ điều gì, chỉ cần đọc từ tập tin. – anru

-1

Bạn cần một cách để đồng bộ hóa các chuỗi đó. Có các giải pháp khác nhau để mutex http://en.wikipedia.org/wiki/Mutual_exclusion

+0

nếu tôi đồng bộ hóa các chủ đề đó, sau đó nó không phải là đọc tập tin cùng một lúc, nó sẽ trở thành một chuỗi đọc, phải không? – anru

+0

Ngay nếu tệp đó không được viết bằng luồng/ổ cắm khác. Nếu trong trường hợp của bạn, bạn chỉ muốn đọc nhưng từ các phần khác nhau, Tại sao không phân tích cú pháp toàn bộ tập tin một lần đầu tiên vào 4 lọ bạn cần? – ktulur

-1

Ông muốn đọc từ một tệp trong các chủ đề khác nhau. Tôi đoán rằng sẽ là ok nếu tập tin được mở ra như là chỉ đọc bởi mỗi thread.

Tôi hy vọng bạn không muốn thực hiện điều này vì hiệu suất, vì bạn sẽ phải quét các phần lớn của tệp cho các ký tự dòng mới trong mỗi chuỗi.

+0

tại sao cần phải tìm kiếm dòng mới char? – anru

+0

bạn phải biết tại đó bù đắp trong dòng tập tin 1000, 2000, 3000, và như vậy, bắt đầu. – Jonatan

+0

anh ta đang truy cập byte chứ không phải đường kẻ - vì vậy không cần phải quan tâm đến điều đó. – Francis

0

Bạn không cần phải làm gì đặc biệt thông minh nếu tất cả những gì họ đang làm đang đọc. Rõ ràng bạn có thể đọc nó nhiều lần song song như bạn muốn, miễn là bạn không độc quyền khóa nó. Viết rõ ràng là một vấn đề khác của khóa học ...

Tôi phải tự hỏi tại sao bạn muốn mặc dù - nó sẽ có khả năng hoạt động tồi tệ vì HDD của bạn sẽ lãng phí rất nhiều thời gian tìm kiếm qua lại thay vì đọc tất cả trong một (tương đối) quét không bị gián đoạn. Đối với các tệp nhỏ (như ví dụ dòng 4000 của bạn), nơi mà có thể không phải là vấn đề như vậy, nó có vẻ không đáng để gây rắc rối.

+0

Tùy thuộc vào loại ổ đĩa, bạn có thể có hiệu suất tốt hơn - ví dụ với ổ đĩa trạng thái rắn (tốt), chúng sẽ mang lại hiệu suất đa luồng tốt. –

+0

Làm thế nào để không độc quyền khóa tập tin và đọc từ nó? –

2

Tôi không thấy bất kỳ lợi thế thực sự nào để thực hiện việc này.
Bạn có thể có nhiều chủ đề đọc từ thiết bị nhưng nút cổ chai của bạn sẽ không phải là CPU mà là tốc độ IO đĩa.

Nếu bạn không cẩn thận, bạn thậm chí có thể làm chậm quá trình xuống (nhưng bạn sẽ cần phải đo lường nó để biết chắc chắn).

+1

Nếu anh ta có một cuộc đột kích hay SSD tốt, điều này có thể không quá tệ, nhưng là điểm tốt. +1 –

+0

Điểm tốt nhưng điều này sẽ đặc biệt hữu ích nếu chi phí xử lý của một dòng vượt quá chi phí truy cập đĩa ... –

0

Có thể mặc dù tôi không chắc chắn nó sẽ có giá trị nỗ lực. Bạn đã xem xét việc đọc toàn bộ tệp vào bộ nhớ trong một chuỗi duy nhất và sau đó cho phép nhiều luồng truy cập dữ liệu đó?

0

Đọc: Không cần khóa tệp. Chỉ cần mở tệp dưới dạng chỉ đọc hoặc được chia sẻ đọc

Viết: Sử dụng mutex để đảm bảo tệp chỉ được viết bởi một người.

0

Như những người khác đã lưu ý, không có vấn đề cố hữu trong việc có nhiều luồng được đọc từ cùng một tệp, miễn là chúng có bộ mô tả/xử lý tệp riêng của chúng. Tuy nhiên, tôi hơi tò mò về động cơ của bạn. Tại sao bạn muốn đọc một tệp song song? Nếu bạn chỉ đọc một tập tin vào bộ nhớ, nút cổ chai của bạn có khả năng là bản thân đĩa, trong trường hợp đó nhiều luồng sẽ không giúp bạn chút nào (nó sẽ chỉ làm lộn xộn mã của bạn). Bạn có thể dễ dàng hiểu, làm việc, giải pháp và (2) bạn đã đo mã của mình để biết bạn nên tối ưu hóa ở đâu.

+0

Mã này để đọc các dòng cụ thể từ một tệp có hoạt động trong các luồng khác nhau không? Đọc cùng một tệp và nhiều dòng mỗi http: //rosettacode.org/wiki/Read_a_specific_line_from_a_file#C –

4

Thậm chí không có vấn đề lớn viết vào cùng một tệp, trung thực.

Đến nay, cách dễ nhất là chỉ ghi nhớ bản đồ tệp. Hệ điều hành sau đó sẽ cung cấp cho bạn một khoảng trống * nơi tệp được ánh xạ vào bộ nhớ. Truyền nó tới một char [], và đảm bảo rằng mỗi luồng sử dụng các mảng con không chồng chéo.

void foo(char* begin, char*end) { /* .... */ } 
void* base_address = myOS_memory_map("example.binary"); 
myOS_start_thread(&foo, (char*)base_address, (char*)base_address + 1000); 
myOS_start_thread(&foo, (char*)base_address+1000, (char*)base_address + 2000); 
myOS_start_thread(&foo, (char*)base_address+2000, (char*)base_address + 3000); 
+0

Các chức năng này bạn đang sử dụng là gì? myOS_start_thread và myOS_memory_map? Tôi không thể tìm thấy những thứ này bằng ngôn ngữ c? và vui lòng giải thích câu trả lời của bạn theo cách dễ dàng hơn? thanks –

+1

@ FarazAhmad: Đó là bởi vì họ đang cố ý giả tên. Thay thế bằng bất kỳ hệ điều hành nào của bạn sử dụng. Ngoài ra, câu trả lời có trước C++ 11 nên tôi không thể sử dụng 'std :: thread'. – MSalters

2

Windows hỗ trợ chồng chéo I/O, cho phép một chuỗi duy nhất xếp hàng không đồng bộ nhiều yêu cầu I/O để có hiệu suất tốt hơn. Điều này có thể được sử dụng bởi nhiều chủ đề đồng thời miễn là tệp bạn đang truy cập hỗ trợ tìm kiếm (nghĩa là đây không phải là đường ống).

Chuyển FILE_FLAG_OVERLAPPED đến CreateFile() cho phép đọc và ghi đồng thời trên cùng một tay cầm tệp; nếu không, Windows sẽ tuần tự hóa chúng. Chỉ định bù đắp tệp bằng cách sử dụng các cấu trúc OffsetOffsetHigh của cấu trúc OVERLAPPED.

Để biết thêm thông tin, hãy xem Synchronization and Overlapped Input and Output.

1

Cách dễ nhất là mở tệp trong từng trường hợp song song, nhưng chỉ cần mở tệp đó dưới dạng chỉ đọc.

Những người nói có thể có một nút cổ chai IO có lẽ là sai. Mọi hệ điều hành hiện đại đều lưu trữ tệp tin đọc. Có nghĩa là lần đầu tiên bạn đọc một tệp sẽ là chậm nhất và mọi lần đọc tiếp theo sẽ nhanh như chớp. Một tập tin 4000 byte thậm chí có thể nghỉ ngơi bên trong bộ nhớ cache của bộ xử lý.

0
std::mutex mtx; 

void worker(int n) 
{ 
    mtx.lock(); 

    char * memblock; 

    ifstream file ("D:\\test.txt", ios::in); 

    if (file.is_open()) 
    { 
     memblock = new char [1000]; 
     file.seekg (n * 999, ios::beg); 
     file.read (memblock, 999); 
     memblock[999] = '\0'; 

     cout << memblock << endl; 

     file.close(); 
     delete[] memblock; 
    } 
    else 
     cout << "Unable to open file"; 
    mtx.unlock(); 
} 


int main() 
{ 
    vector<std::thread> vec; 
    for(int i=0; i < 3; i++) 
    { 
     vec.push_back(std::thread(&worker,i)); 
    } 

    std::for_each(vec.begin(), vec.end(), [](std::thread& th) 
    { 
     th.join(); 
    }); 
    return 0; 
} 
Các vấn đề liên quan