2013-08-22 26 views
6

Tôi có một hàm trong C tự động phân bổ bộ đệm, được chuyển đến hàm khác để lưu trữ giá trị trả về của nó. Một cái gì đó giống như ví dụ giả sau đây:Con trỏ tĩnh đến bộ đệm được cấp phát động bên trong hàm

void other_function(float in, float *out, int out_len) { 
    /* Fills 'out' with 'out_len' values calculated from 'in' */ 
} 

void function(float *data, int data_len, float *out) { 
    float *buf; 
    int buf_len = 2 * data_len, i; 
    buf = malloc(sizeof(float) * buf_len); 

    for (i = 0; i < data_len; i++, data++, out++) { 
     other_function(*data, buf, buf_len); 
     /* Do some other stuff with the contents of buf and write to *out */ 
    } 
    free buf; 
} 

function được gọi bằng một iterator qua một mảng đa chiều (đó là một gufunc kernel NumPy, để được chính xác), vì vậy nó được gọi là hàng triệu lần với cùng một giá trị data_len. Có vẻ như lãng phí để tạo ra và phá hủy bộ đệm hơn và hơn nữa. Tôi thường di chuyển việc cấp phát bộ đệm cho hàm gọi function và chuyển poiinter cho nó, nhưng tôi không trực tiếp kiểm soát điều đó, vì vậy không thể. Thay vào đó, tôi đang xem xét cách làm như sau:

void function(float *data, int data_len, float *out) { 
    static float *buf = NULL; 
    static int buf_len = 0; 
    int i; 
    if (buf_len != 2 * data_len) { 
     buf_len = 2 * data_len; 
     buf = realloc(buf, sizeof(float) * buf_len); /* same as malloc if buf == NULL */ 
    } 
    for (i = 0; i < data_len; i++, data++, out++) { 
     other_function(*data, buf, buf_len); 
     /* Do some other stuff with the contents of buf and write to *out */ 
    } 
} 

đó có nghĩa là tôi không bao giờ trực tiếp giải phóng bộ nhớ tôi phân bổ: nó được tái sử dụng trong các cuộc gọi tiếp theo, và sau đó lưu lại đó cho đến khi thoát chương trình của tôi. Nó không có vẻ giống như việc phải làm, nhưng cũng không quá tệ, vì lượng bộ nhớ được phân bổ luôn nhỏ. Tôi có quá lo lắng không? Có cách tiếp cận tốt hơn cho điều này?

+0

Bạn có guarentees nào về kích thước của bộ đệm động không? –

+0

không có raii trong C, có thể trình biên dịch bạn sử dụng có phần mở rộng raii như trong gcc: http://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html –

+0

@JustinMeiners Có, nó được kiểm soát rất chặt chẽ. Tối đa là 65536 mặt hàng, nhưng đó là hiếm, thường dài 16 hoặc 32 mặt hàng. – Jaime

Trả lời

5

Cách tiếp cận này là hợp pháp (nhưng xem bên dưới), mặc dù các công cụ như valgrind sẽ gắn cờ không chính xác nó là "rò rỉ". (Nó không phải là một rò rỉ, vì rò rỉ là một sự gia tăng không bị chặn trong việc sử dụng bộ nhớ.) Bạn có thể muốn đo điểm chính xác mất bao nhiêu thời gian trên mallocfree so với các chức năng khác mà chức năng đang thực hiện. Nếu bạn có thể sử dụng C99 hoặc gcc và nếu bộ đệm của bạn không quá lớn, bạn cũng nên xem xét các mảng có độ dài thay đổi, nhanh hơn (hoặc nhanh hơn) một bộ đệm tĩnh và không tạo phân mảnh. Nếu bạn đang sử dụng một trình biên dịch khác, bạn có thể xem xét phần mở rộng alloca không chuẩn (nhưng widelysupported) alloca.

Bạn cần phải nhận thức rằng việc sử dụng một bộ đệm tĩnh làm cho chức năng của bạn:

  1. Thread-an toàn - nếu nó được gọi là từ nhiều luồng đồng thời, nó sẽ phá hủy các dữ liệu của các ví dụ khác. Nếu Python được gọi từ numpy, điều này có lẽ không phải là một vấn đề, vì các chủ đề sẽ được tuần tự hóa hiệu quả bởi GIL.

  2. Không reentrant - nếu other_function gọi một số mã Python kết thúc bằng cách gọi function - vì bất kỳ lý do gì - trước khi function kết thúc, chức năng của bạn sẽ lại phá hủy dữ liệu của riêng nó.

Nếu bạn không cần phải thực hiện song song đúng và reentrancy, sử dụng này static biến là tốt, và rất nhiều mã C sử dụng chúng theo cách đó.

+0

Điểm tốt về chủ đề an toàn ... Nếu điều này bao giờ được song song nó sẽ là với 'multiprocessing'. Mỗi quá trình sẽ nhận được bản sao riêng của biến tĩnh? – Jaime

+1

@Jaime Có - các quy trình riêng biệt không chia sẻ các biến toàn cục. – user4815162342

2

Đây là một cách tiếp cận tốt và một cái gì đó như thế này có thể được sử dụng trong nội bộ bởi nhiều thư viện. Bộ nhớ sẽ được giải phóng tự động khi chương trình thoát.

Bạn có thể muốn làm tròn buf_len tối đa nhiều kích thước khối, vì vậy bạn không realloc() mỗi lần data_len thay đổi một chút. Nhưng nếu data_len hầu như luôn có cùng kích thước, điều này là không cần thiết.

Các vấn đề liên quan