2012-05-23 15 views
6

Python içinde önce çoklu kütüphane kullanmış, ama bu işçilerin havuzu oluşturmak istiyorum C. I parçacığı çalışıyorum ilk defa. Buna karşılık, sözde bu işçiler için itmek veya kod henüz oldukça yoktur queue.Following gelen pop, ama şimdiye kadar yapmış budur:nasıl uygulanır parçacığı güvenli kuyruklar

#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); 
} 

kod yukarıda çalıştı ve her zaman tam olarak her isim baskılı bir Zamanlar. Herhangi bir isim atlamadı veya iki kez aynı adı basmadı. Öte yandan, bu kuyruğun uygulanmasının güvenliğini nasıl sağladığından emin değilim. Yani sorum şu: Bu bir threadafe kuyruğu mu? Değilse neden olmasın? Ve nasıl iş parçacığı güvenli hale getirmek için?

+0

Yapıların yazım hataları gerekmez; zaten bir türü var. –

cevap

5

Bu kod parçacığı güvenli değil.

itme ve pop fonksiyonları parçacığı güvenli değildir. Kodda, itme sadece tek bir iş parçacığı tarafından yürütülür, bu yüzden fark etmez, ancak pop'lar birden çok iş parçacığı tarafından yürütülür.

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

düşünün iplik bir o zamana kadar yürütür ve hat 4. İplik bir yürütülmesine devam içeren ve hat 2. Dişlerin B içeren kadar çalıştırır. Q-> kafasının zaten özgür olduğunu() buldu. Şimdi, bu şimdiye kadar mantıklı konuları tartışıyor. Bununla birlikte, dikkate alınması gereken fiziksel sorunlar vardır.

bir seferde sadece bir dişin 1, 4 için, örneğin kod yürütebilir bu tür lifler davranışlarını eşzamanlı olabilir, burada bir kilitleme mekanizması, ve hayal Bir nesne sadece bir iş parçacığı olan bir muteks, bir seferde 'tutabilir', ve mutex elde etmeye çalışmak, tutulan iplik serbest kalana kadar iş parçacığı bloklar. Görünür hemen sadece bu çekirdek üzerine ipliklerine olan

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 

hala bir sorun olurdu ki, herhangi bir işlemci çekirdeği tarafından gerçekleştirilen yazma (iplik değil); diğer çekirdeklerdeki konulara değil.

sadece yürütme sychronize için yeterli değildir; Aynı zamanda, bir çekirdeğin gerçekleştirdiği yazıların diğer çekirdeklere görünür hale gelmesini sağlamalıyız.

(Un) neyse, tüm modern sychronization yöntemleri de ateş basması bu yazma gerçekleştirmek (bir muteksi olsun mesela, aynı zamanda floş tüm belleğe yazar). Maalesef, çünkü bu davranışa ihtiyacınız yok çünkü performansa zarar veriyor.

3

Bu evreli değildir birden fazla parçacığı, potansiyel olarak bozulmasını aynı zamanda bağlantılı hale getirilmiş liste içinde işaretçiler değişiklikler olabileceği için. Orada Multiple-writer thread-safe queue in C

Eğer kuyruk evreli nasıl görebiliriz: Burada

Eğer çok benzer bir soru için bir cevabım var.

İlgili konular