2009-04-27 37 views
5

Tôi đã đi sâu hơn vào C++ gần đây và các lỗi của tôi dường như trở nên phức tạp.C++: Dữ liệu đọc có thể ảnh hưởng đến bộ nhớ như thế nào?

Tôi có vectơ các đối tượng, mỗi đối tượng chứa một vectơ nổi. Tôi quyết định tôi cần tạo một mảng phẳng hơn chứa tất cả các giá trị float của tất cả các đối tượng trong một. Nó phức tạp hơn một chút nhưng ý chính của vấn đề là khi tôi lặp qua các đối tượng của tôi giải nén các giá trị float, tại một thời điểm nào đó, vật thể của tôi bị thay đổi, hoặc bị hỏng theo một cách kỳ lạ nào đó. (Các hoạt động đọc của tôi là tất cả các hàm const)

Một ví dụ khác là với MPI. Tôi chỉ mới bắt đầu vì vậy tôi chỉ muốn chạy chính xác cùng một mã trên hai nút khác nhau với bộ nhớ riêng của họ và không có truyền dữ liệu xảy ra, tất cả rất đơn giản. Trước sự ngạc nhiên của tôi, tôi có lỗi phân đoạn và sau khi theo dõi giờ, tôi thấy rằng một nhiệm vụ của một biến đã đặt một biến hoàn toàn khác thành NULL.

Vì vậy, tôi tò mò, làm thế nào có thể là hoạt động đọc có thể ảnh hưởng đến cấu trúc dữ liệu của tôi. Tương tự như thế nào một hoạt động dường như không liên quan ảnh hưởng đến một hoạt động khác. Tôi không thể mong đợi các giải pháp cho vấn đề của tôi với những mô tả ngắn gọn nhưng lời khuyên nào sẽ được đánh giá cao.

Cập nhật: Đây là một đoạn mã, tôi không đăng bài ban đầu vì tôi không chắc chắn bao nhiêu có thể được trích xuất từ ​​nó mà không hiểu toàn bộ hệ thống.

Một điều tôi chỉ phát hiện ra mặc dù là khi tôi ngừng gán giá trị cho mảng phẳng của tôi và chỉ cout'ed thay vào đó, các lỗi seg biến mất. Vì vậy, có lẽ tôi tuyên bố mảng của tôi sai, nhưng ngay cả khi tôi là tôi không chắc chắn làm thế nào nó sẽ ảnh hưởng đến vector đối tượng.

void xlMasterSlaveGpuEA::FillFlatGenes() { 
    int stringLength = pop->GetGenome(0).GetLength(); 
    for (int i=0;i<pop->GetPopSize();i++) 
     for (int j=0;j<stringLength;j++) 
      flatGenes[(i*stringLength)+j]<< pop->GetGenome(i).GetFloatGene(j); 
} 

float xlVectorGenome::GetFloatGene(unsigned int i) const { 
    return GetGene(i); 
} 

mảng căn hộ của tôi là một hàm thành viên

float * flatFitness; 

initailsed trong constructor như vậy:

flatFitness = new float(popSize); 

Cập nhật 2:

Tôi chỉ muốn chỉ ra rằng hai ví dụ trên không liên quan, ví dụ đầu tiên không phải là đa luồng. Ví dụ MPI thứ hai là về mặt kỹ thuật, nhưng Bộ KH & ĐT được phân phối bộ nhớ và tôi cố tình thực hiện triển khai đơn giản nhất mà tôi có thể nghĩ đến, đó là cả hai máy chạy mã độc lập. tuy nhiên có một chi tiết thêm, tôi đặt trong một condtional nói

if node 1 then do bottom half of loop 

if node 1 then do top half 

Một lần nữa, bộ nhớ cần được cô lập, họ nên làm việc như thể họ không biết gì về nhau .. nhưng loại bỏ điều kiện này và làm cho cả hai vòng làm tất cả các hình khối, loại bỏ lỗi

+0

Bạn có thể đăng phiên bản mã bị cô đặc không? Rất khó để nói từ điều này những gì có thể xảy ra. – tgamblin

+0

Bạn có thể đăng mã vòng lặp nơi bạn lặp lại các đối tượng trong vectơ ... có thể bạn đang bước vào bộ nhớ ở đó? – Balk

+1

Thao tác đọc không thay đổi giá trị. Phải có cái gì đó khác trong mã của bạn. Ví dụ thứ hai của bạn là một tình huống điển hình của một biến trỏ đến địa điểm sai. – fbinder

Trả lời

14

Đây không phải là một nhà xây dựng mảng:

01.
float * flatFitness; 
flatFitness = new float(popSize); 

Bạn đang tạo một phao trên heap tại đây, được khởi tạo với giá trị popSize. Nếu bạn muốn một mảng nổi bạn cần sử dụng dấu ngoặc vuông thay vì dấu ngoặc đơn:

float *flatFitness = new float[popSize]; 

Điều này có thể dễ dàng gây ra sự cố bạn mô tả. Ngoài ra, hãy nhớ khi bạn tạo mảng, bạn cần phải xóa bằng cách sử delete [] (cuối cùng):

delete [] flatFitness; 

Nếu bạn chỉ cần sử dụng delete, nó có thể làm việc, nhưng hành vi này là không xác định.

Nếu bạn muốn tránh sử dụng cú pháp mảng hoàn toàn, tại sao không sử dụng std::vector? Bạn có thể tạo một vector của các yếu tố popSize như thế này:

#include <vector> 

std::vector<float> flatFitness(popSize); 

này sẽ được giải phóng tự động khi nó rơi ra khỏi phạm vi, vì vậy bạn không cần phải lo lắng về new hoặc delete.

Cập nhật (lại: nhận xét): Nếu bạn đã sử dụng std::vectors ở nơi khác trong mã của mình, hãy xem std::vector::swap(). Bạn có thể tránh sao chép mọi thứ hoàn toàn và chỉ cần trao đổi một vài vectơ qua lại giữa bộ đệm cho CUDA và quá trình xử lý bạn đang làm ở đây.

+0

cảm ơn, tôi sẽ kiểm tra rằng ra – zenna

+0

funnily đủ Tôi đang trích xuất dữ liệu từ std :: vectơ như tôi cần phải gửi nó đến GPU thông qua CUDA. Có lẽ một cách thanh lịch hơn rất nhiều – zenna

+0

Hãy xem vector :: swap(). Bạn có thể khởi tạo một số vectơ ở đây, sau đó hoán đổi chúng với những cái bạn sử dụng cho CUDA để bạn không phải thực hiện bất kỳ việc sao chép nào cả. Chỉ cần đảm bảo rằng chúng có kích thước phù hợp bằng cách sử dụng resize() hoặc hàm khởi tạo (như trên), hoặc bạn có thể sẽ ghi vào bộ nhớ mà bạn không có. – tgamblin

0

Tôi nghi ngờ bạn có vấn đề về tham nhũng đa luồng hoặc bộ nhớ mà bạn không biết. Hành vi bạn mô tả không phải là bất kỳ loại hành vi tiêu chuẩn, thiết kế, mong muốn nào.

+0

Có, điều này nghe giống như trường hợp gần như sách giáo khoa thiếu rào cản bộ nhớ và không đồng bộ hóa liên tục. Nó chỉ mất một chủ đề để cập nhật đối tượng dữ liệu tại một số điểm sau khi nó trở nên hiển thị với một luồng khác và việc thiếu đồng bộ hóa sẽ cắn bạn sớm hay muộn. –

+1

Có thể, ngoại trừ ông không bao giờ nói rằng ông đã sử dụng chủ đề. MPI là song song cấp độ quá trình, trừ khi bạn kết hợp nó với cái gì khác. – tgamblin

+0

Heh, không có mã nào được đăng khi tôi trả lời. –

-1

jeffamaphone có thể đúng rằng đây là vấn đề về luồng. Một khả năng khác là các đối tượng mà bạn đang đọc đã bị xóa. Sau đó, bạn sẽ đọc từ một địa chỉ không hợp lệ. Nó cũng có thể là các cấu trúc dữ liệu bạn đang viết vào lúc này được lưu trữ tại cùng một vị trí mà các vectơ trước đây chiếm đóng. Điều này sẽ dẫn đến hành vi bạn mô tả.

EDIT (dựa trên bản cập nhật của bạn):

này có thể bị lỗi: stringLength được khởi tạo bên ngoài của các vòng ngoài, nhưng có vẻ như nó cần phải được cập nhật trong thời gian đó vòng ngoài:

int stringLength = pop->GetGenome(0).GetLength(); 
for (int i=0;i<pop->GetPopSize();i++) 
    for (int j=0;j<stringLength;j++) 
     flatGenes[(i*stringLength)+j]<< pop->GetGenome(i).GetFloatGene(j); 

sửa chữa đề nghị:

for (int i=0;i<pop->GetPopSize();i++) { 
    int stringLength = pop->GetGenome(i).GetLength(); 
    for (int j=0;j<stringLength;j++) { 
     flatGenes[(i*stringLength)+j]<< pop->GetGenome(i).GetFloatGene(j); 
    } 
} 
Các vấn đề liên quan