2011-10-31 34 views
20

Tôi tạo một chuỗi và đặt nó vào một vòng lặp vô hạn. Tôi bị rò rỉ bộ nhớ khi kiểm tra mã với valgrind. Đây là mã của tôi:Làm thế nào tôi có thể giết một pthread đó là trong một vòng lặp vô hạn, từ bên ngoài vòng lặp đó?

#include <pthread.h> 
#include <time.h> 

void thread_do(void){ 
    while(1){} 
} 

int main(){ 
    pthread_t th; 
    pthread_create(&th, NULL, (void *)thread_do, NULL); 

    sleep(2); 
    /* I want to kill thread here */ 
    sleep(2); 
    return 0; 
} 

Vì vậy, một chuỗi được tạo trong chính và chỉ chạy thread_do() mọi lúc. Có cách nào để giết nó từ bên trong chính sau 2 giây không? Tôi đã thử cả hai pthread_detach(th)pthread_cancel(th) nhưng tôi vẫn bị rò rỉ.

+3

Hủy bỏ pthreads có nghĩa là các chủ đề không có cơ hội để làm sạch bất kỳ bộ nhớ nó được phân bổ. –

+2

Ok tôi đã giải quyết vấn đề này bằng cách chỉ có 'keepalive = 1' toàn cục. Sau đó, tôi đã thay đổi 'while (1)' thành 'while (keepalive)'. Để giết các chủ đề bây giờ tôi chỉ cần thay đổi giá trị của biến keepalive 0 và thì đấy! – Pithikos

Trả lời

32

Như @sarnold chỉ ra, theo mặc định chủ đề của bạn không thể bị hủy bỏ với pthread_cancel() mà không gọi bất kỳ chức năng mà là những điểm hủy ... nhưng điều này có thể được thay đổi bằng cách sử dụng pthread_setcanceltype() để đặt loại hủy của chuỗi thành không đồng bộ thay vì trì hoãn. Để làm điều đó, bạn sẽ thêm một cái gì đó như pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL); gần bắt đầu chức năng chuỗi của bạn, trước khi bạn bắt đầu vòng lặp. Sau đó, bạn có thể chấm dứt chuỗi bằng cách gọi pthread_cancel(th) từ main().

Lưu ý, mặc dù, hủy chuỗi theo cách này (dù không đồng bộ hay không) sẽ không dọn sạch bất kỳ tài nguyên nào được phân bổ trong hàm chuỗi (như chú thích của Kevin trong nhận xét). Để làm được điều này sạch sẽ, bạn có thể:

  • Đảm bảo rằng các thread không làm bất cứ điều gì nó cần để làm sạch trước khi xuất cảnh (ví dụ sử dụng malloc() phân bổ một bộ đệm)
  • Đảm bảo rằng bạn có một số cách làm sạch sau khi chỉ ở nơi khác, sau khi thoát khỏi luồng
  • Sử dụng pthread_cleanup_push()pthread_cleanup_pop() để thêm trình xử lý dọn dẹp để dọn sạch tài nguyên khi chuỗi bị hủy. Lưu ý rằng điều này vẫn còn nguy hiểm nếu loại hủy không đồng bộ, vì chuỗi có thể bị hủy giữa phân bổ tài nguyên và thêm trình xử lý dọn dẹp.
  • Tránh sử dụng pthread_cancel() và yêu cầu kiểm tra một số điều kiện để xác định thời điểm kết thúc (sẽ được kiểm tra trong các vòng chạy dài). Kể từ khi chủ đề của bạn sau đó kiểm tra cho chấm dứt chính nó, nó có thể làm bất cứ điều gì làm sạch nó cần phải sau khi kiểm tra.

Một cách để thực hiện lựa chọn cuối cùng là sử dụng một mutex như một lá cờ, và thử nghiệm nó với pthread_mutex_trylock() bọc trong một chức năng để sử dụng trong các bài kiểm tra vòng lặp:

#include <pthread.h> 
#include <unistd.h> 
#include <errno.h> 

/* Returns 1 (true) if the mutex is unlocked, which is the 
* thread's signal to terminate. 
*/ 
int needQuit(pthread_mutex_t *mtx) 
{ 
    switch(pthread_mutex_trylock(mtx)) { 
    case 0: /* if we got the lock, unlock and return 1 (true) */ 
     pthread_mutex_unlock(mtx); 
     return 1; 
    case EBUSY: /* return 0 (false) if the mutex was locked */ 
     return 0; 
    } 
    return 1; 
} 

/* Thread function, containing a loop that's infinite except that it checks for 
* termination with needQuit() 
*/ 
void *thread_do(void *arg) 
{ 
    pthread_mutex_t *mx = arg; 
    while(!needQuit(mx)) {} 
    return NULL; 
} 

int main(int argc, char *argv[]) 
{ 
    pthread_t th; 
    pthread_mutex_t mxq; /* mutex used as quit flag */ 

    /* init and lock the mutex before creating the thread. As long as the 
    mutex stays locked, the thread should keep running. A pointer to the 
    mutex is passed as the argument to the thread function. */ 
    pthread_mutex_init(&mxq,NULL); 
    pthread_mutex_lock(&mxq); 
    pthread_create(&th,NULL,thread_do,&mxq); 

    sleep(2); 

    /* unlock mxq to tell the thread to terminate, then join the thread */ 
    pthread_mutex_unlock(&mxq); 
    pthread_join(th,NULL); 

    sleep(2); 
    return 0; 
} 

Nếu thread không phải là tách ra (nó thường không theo mặc định), bạn nên gọi pthread_join() sau khi dừng chuỗi.Nếu thread được tách ra, bạn không cần phải tham gia nó, nhưng bạn sẽ không biết chính xác khi nào nó chấm dứt (hoặc thậm chí xấp xỉ, trừ khi bạn thêm một cách khác để chỉ ra lối ra của nó).

+0

để sử dụng giải pháp mutex này cho nhiều pthread tôi sẽ cần một mutex cho mỗi chủ đề, phải không? bạn có đề xuất giải pháp này trong trường hợp này không? –

+2

@RicardoCrudo Không, chỉ một mutex ... nếu 'needQuit()' khóa thành công nó, nó mở khóa nó ngay sau khi ... chỉ 'main()' giữ mutex trong một khoảng thời gian dài. Bất kỳ chủ đề nào sử dụng 'needQuit()' để kiểm tra xem có bỏ thuốc lá sẽ bỏ khi không có gì khác bị khóa mutex, và chúng sẽ chỉ tự khóa nó trong một khoảnh khắc (rất ngắn). Chỉ một cuộc gọi 'needQuit()' sẽ thành công tại một thời điểm, nhưng mỗi thread sẽ vẫn nhận được một cuộc gọi thành công cái khác. – Dmitri

5

Một vài suy nghĩ nhỏ:

  1. Bạn đang cố gắng hủy thread của bạn, nhưng nếu chính sách hủy tại chỗ là một hủy chậm, bạn thread_do() sẽ không bao giờ bị hủy bỏ, bởi vì nó không bao giờ gọi bất kỳ các chức năng là các điểm hủy:

    A thread's cancellation type, determined by 
    pthread_setcanceltype(3), may be either asynchronous or 
    deferred (the default for new threads). Asynchronous 
    cancelability means that the thread can be canceled at any 
    time (usually immediately, but the system does not guarantee 
    this). Deferred cancelability means that cancellation will 
    be delayed until the thread next calls a function that is a 
    cancellation point. A list of functions that are or may be 
    cancellation points is provided in pthreads(7). 
    
  2. Bạn không tham gia chuỗi trong mã ví dụ đơn giản của mình; gọi pthread_join(3) trước khi kết thúc chương trình của bạn:

    After a canceled thread has terminated, a join with that 
    thread using pthread_join(3) obtains PTHREAD_CANCELED as the 
    thread's exit status. (Joining with a thread is the only way 
    to know that cancellation has completed.) 
    
Các vấn đề liên quan