2012-05-23 22 views
6

Tôi đã sử dụng thư viện đa luồng trước trong Python, nhưng đây là lần đầu tiên tôi thử luồng trong C. Tôi muốn tạo nhóm công nhân. Đổi lại, những người lao động phải đẩy tới hoặc bật từ queue.Following mã không khá có được nêu ra, nhưng là những gì tôi đã làm cho đến nay:Làm thế nào để thực hiện hàng đợi an toàn thread

#include <stdio.h> 
#include <stdlib.h> 
#include <pthread.h> 
#define NUMTHREADS 20 /* number of threads to create */ 

typedef struct node node; 
typedef struct queue queue; 

struct node { 
    char *name; 
    node *next; 
}; 

struct queue { 
    node *head; 
    node *tail; 
}; 

/* pop: remove and return first name from a queue */ 
char *pop(queue *q) 
{ 
    if (q->head == NULL) 
     return NULL; 
    char *name = q->head->name; 
    node *tmp = q->head; 
    q->head = q->head->next; 
    free(tmp); 
    return name; 
} 

/* push: add name to the end of the queue */ 
int push(queue *q, char *name) 
{ 
    node *new = malloc(sizeof(node)); 
    if (new == NULL) 
     return -1; 
    new->name = name; 
    new->next = NULL; 
    if (q->tail != NULL) 
     q->tail->next = new; 

    q->tail = new; 
    if (q->head == NULL) /* first value */ 
     q->head = new; 
    return 0; 
} 

/* printname: get a name from the queue, and print it. */ 
void *printname(void *sharedQ) 
{ 
    queue *q = (queue *) sharedQ; 
    char *name = pop(q); 
    if (name == NULL) 
     pthread_exit(NULL); 
    printf("%s\n",name); 
    pthread_exit(NULL); 
} 

int main() 
{ 
    size_t i; 
    int rc; 
    pthread_t threads[NUMTHREADS]; 
    char *names[] = { 
     "yasar", 
     "arabaci", 
     "osman", 
     "ahmet", 
     "mehmet", 
     "zeliha" 
    }; 

    queue *q = malloc(sizeof(queue)); 
    q->head = NULL; 
    q->tail = NULL; 

    /* number of elements in the array */ 
    size_t numelems = sizeof(names)/sizeof(char *); 

    for (i = 0; i < numelems; i++) /* push each name */ 
     push(q, names[i]); 

    for (i = 0; i < NUMTHREADS; i++) { /* fire up threads */ 
     rc = pthread_create(&threads[i], NULL, printname, 
       (void *)q); 
     if (rc) { 
      printf("Error, return code from pthread is %d\n", rc); 
      exit(-1); 
     } 
    } 

    pthread_exit(NULL); 
} 

tôi đã cố gắng trên mã, và nó luôn luôn được in mỗi tên chính xác Một lần. Nó không bỏ qua bất kỳ tên nào, hoặc in cùng một tên hai lần. Mặt khác, tôi không chắc chắn cách luồng an toàn thực hiện hàng đợi này. Vì vậy, câu hỏi của tôi là, Đây có phải là một hàng đợi threadsafe? Nếu không, tai sao không? Và làm thế nào để làm cho nó thread an toàn?

+0

Cấu trúc không cần typedef; họ đã có một loại rồi. –

Trả lời

5

Mã không phải là chủ đề an toàn.

Chức năng push và pop không phải là chủ đề an toàn. Trong mã, lệnh push chỉ được thực hiện bởi một luồng đơn, do đó, nó không quan trọng, nhưng các pops đang được thực thi bởi nhiều luồng.

Tưởng tượng luồng A thực thi lên và bao gồm dòng 2. Chuỗi B sau đó thực thi lên và bao gồm dòng 4. Thread A tiếp tục thực hiện. Nó thấy rằng q-> đầu đã được miễn phí() ed.

Bây giờ, điều này cho đến nay bàn về các vấn đề logic.

Tuy nhiên, có các vấn đề vật lý cần xem xét.

Hãy tưởng tượng chúng tôi có cơ chế khóa trong đó các chủ đề có thể đồng bộ hóa hành vi của chúng, như vậy chỉ có một luồng tại một thời điểm có thể thực thi mã trong các dòng từ 1 đến 4, ví dụ: một mutex, mà là một đối tượng chỉ có một thread có thể 'giữ' tại một thời điểm, và nơi cố gắng để có được mutex khối thread cho đến khi các thread giữ phát hành.

0. get mutex 
1. char *name = q->head->name; 
2. node *tmp = q->head; 
3. q->head = q->head->next; 
4. free(tmp); 
5. release mutex 

Chúng tôi vẫn gặp sự cố, trong đó ghi được thực hiện bởi bất kỳ lõi CPU nào (không phải chuỗi) chỉ hiển thị ngay trên các chuỗi trên lõi đó; không đề cập đến các lõi khác.

Nó không đủ để thực hiện đồng bộ hóa; đồng thời, chúng ta cũng phải đảm bảo việc ghi được thực hiện bởi một lõi trở nên hiển thị với các lõi khác.

(Un) may mắn thay, tất cả các phương pháp đồng bộ hóa hiện đại cũng thực hiện thao tác ghi này (ví dụ: khi bạn nhận được mutex, bạn cũng xóa tất cả ghi vào bộ nhớ). Tôi nói thật không may, bởi vì bạn không-đường-cần hành vi này và nó có hại cho hiệu suất.

3

Nó không an toàn bởi vì nhiều chủ đề có thể sửa đổi các con trỏ trong danh sách liên kết cùng một lúc, có khả năng làm hỏng nó.

Ở đây bạn có câu trả lời cho một câu hỏi rất giống nhau: Multiple-writer thread-safe queue in C

Ở đó bạn có thể tham khảo cách làm cho hàng đợi thread-safe.

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