2012-04-16 29 views
6

Tôi đã viết một chương trình đã viết và nó không hoạt động như tôi mong đợi. Tôi có hai chủ đề: thread kích hoạt funcanotherThread gây ra anotherFunc. Những gì tôi muốn làm là khi cont đạt giá trị 10 trong func, anotherThread được kích hoạt bằng cách sử dụng pthread_cond_waitpthread_cond_signal. Điều kỳ lạ là mọi thứ hoạt động tốt nếu tôi bỏ ghi chú dòng sleep(1). Tôi mới vào chủ đề và tôi đã làm theo các hướng dẫn here và nếu tôi nhận xét dòng sleep trong ví dụ của họ nó phá vỡ là tốt.Chủ đề POSIX C. ví dụ pthread_cond_t. Không hoạt động như mong đợi

Câu hỏi của tôi là làm cách nào để tôi có thể thực hiện tác vụ này mà không cần bất kỳ cuộc gọi nào sleep()? Và điều gì xảy ra nếu trong mã của tôi cả hai số func, hãy truy cập pthread_mutex_lock sau anotherFunc? Làm thế nào tôi có thể kiểm soát những điều này? Đây là mã của tôi:

#include <iostream> 
#include <stdlib.h> 
#include <stdio.h> 
#include <pthread.h> 

pthread_mutex_t myMutex; 
pthread_cond_t cond; 
pthread_attr_t attr; 

int cont; 

void *func(void*) 
{ 
    printf("func\n"); 

    for(int i = 0; i < 20; i++) 
    { 
     pthread_mutex_lock(&myMutex); 

     cont++; 
     printf("%d\n", cont); 
     if(cont == 10) 
     { 
      printf("signal:\n"); 
      pthread_cond_signal(&cond); 
//   sleep(1); 
     } 
     pthread_mutex_unlock(&myMutex); 
    } 
    printf("Done func\n"); 

    pthread_exit(NULL); 
} 

void *anotherFunc(void*) 
{ 
    printf("anotherFunc\n"); 
    pthread_mutex_lock(&myMutex); 
    printf("waiting...\n"); 

    pthread_cond_wait(&cond, &myMutex); 
    cont += 10; 
    printf("slot\n"); 

    pthread_mutex_unlock(&myMutex); 
    printf("mutex unlocked anotherFunc\n"); 
    printf("Done anotherFunc\n"); 

    pthread_exit(NULL); 
} 

int main(int argc, char *argv[]) 
{ 
    pthread_t thread; 
    pthread_t anotherThread; 

    pthread_attr_init(&attr); 
    pthread_mutex_init(&myMutex, NULL); 
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 
    pthread_cond_init(&cond, NULL); 

    pthread_create(&anotherThread, &attr, anotherFunc, NULL); 
    pthread_create(&thread, &attr, func, NULL); 

    pthread_join(thread, NULL); 
    pthread_join(anotherThread, NULL); 

    printf("Done MAIN()"); 

    pthread_mutex_destroy(&myMutex); 
    pthread_cond_destroy(&cond); 
    pthread_attr_destroy(&attr); 


    pthread_exit(NULL); 
    return 0; 
} 

Xin lỗi vì bài viết dài nhưng tôi mới làm chủ đề và tôi sẵn sàng học. Ngoài ra bạn có biết một số tài liệu tham khảo hay các khóa học/hướng dẫn tốt về các chủ đề và kết nối mạng trên Linux không? Tôi muốn học cách tạo một ứng dụng trò chuyện và tôi nghe nói rằng tôi phải biết chủ đề và kết nối mạng cho điều đó. Vấn đề là tôi không biết khá tốt nếu những gì tôi học là ok vì tôi không biết những gì tôi phải biết.

Cảm ơn bạn rất nhiều :)

+0

Các nhận xét khác. Ngoài việc không phải sử dụng 'pthread_attr_t', bạn có thể sử dụng bộ khởi tạo tĩnh cho điều kiện và mutex để đơn giản hóa mã. Hơn nữa, các hàm thread của bạn chỉ có thể trả về NULL, 'hoặc' return 0; 'thay vì gọi' pthread_exit'. Và chủ đề chính của bạn chỉ có thể 'trả về 0;' từ chính mà không gọi 'pthread_exit'. Các chủ đề khác không chạy vào thời điểm đó kể từ khi chúng được tham gia. trở về từ lực lượng chính một quá trình thoát, nhưng 'pthread_exit' trong tiểu học chủ đề không bắt buộc một quá trình xuất cảnh, đó là hữu ích cho việc giữ các chủ đề khác đang chạy. – Kaz

+0

Ngoài ra, không cần phải làm sạch các điều kiện và điều kiện tĩnh. Chỉ cần sử dụng 'pthread_mutex_t myMutex = PTHREAD_MUTEX_INITIALIZER;'. Khởi tạo phức tạp là cần thiết cho các tình huống mà bạn muốn đặt thuộc tính bất thường. Ví dụ. tạo một mutex mạnh mẽ được chia sẻ theo quy trình. – Kaz

Trả lời

9

bạn anotherThread chỉ đơn giản gọi pthread_cond_wait mà không cần thử nghiệm đầu tiên cho dù điều kiện mong muốn (truy cập đạt mười) đã xảy ra rồi. Đây là logic không chính xác, điều này sẽ dẫn đến sự cố đánh thức bị mất: tên của lỗi định kỳ gây ra các chương trình đa luồng được ghi không chính xác.

Biến điều kiện là trạng thái không quốc tịch. Nếu pthread_cond_signal hoặc pthread_cond_broadcast được gọi với điều kiện không có chủ đề nào đang chờ, thao tác sẽ không có hiệu lực. Nó không được nhớ. Vì vậy, nó có thể cho thread tín hiệu của bạn để đếm đến 10 rất nhanh chóng, và báo hiệu biến điều kiện, trước khi thread khác đã đạt đến cuộc gọi pthread_cond_wait.

Bạn cần vòng lặp xung quanh pthread_cond_wait. Điều kiện phải được kiểm tra trong trường hợp nó đã đúng, do đó, các chủ đề không chờ đợi cho một wakeup đã xảy ra. Và nó phải là một vòng lặp vì wakeups có thể giả mạo: chỉ vì sợi rơi qua pthread_cond_wait không có nghĩa là tình trạng này là thực sự đúng:

while (cont < 10) 
    pthread_cond_wait(&cond, &myMutex); 

Ngoài ra, có không cần phải tạo ra một thuộc tính chủ đề chỉ để tạo một chuỗi có thể tham gia. Đây là tình huống mặc định khi bạn sử dụng một con trỏ null cho thuộc tính tạo. Chủ đề POSIX có thể kết nối trừ khi được tạo ra tách rời hoặc được chuyển đổi thành tách rời với pthread_detach.

Một điều khác: bất cứ khi nào có thể, hãy tránh gọi số pthread_cond_signal trong khi giữ khóa mutex. Nó không phải là không chính xác, nhưng nó có thể lãng phí, bởi vì hoạt động thực sự có thể phải gọi vào hạt nhân OS để đánh thức một luồng, và vì vậy bạn đang nắm giữ khóa mutex đắt tiền này trong toàn bộ cuộc gọi hệ thống (khi tất cả bạn thực sự cần nó) đang bảo vệ một vài hướng dẫn máy làm việc với dữ liệu được chia sẻ trong ứng dụng của bạn).

+0

AnotherThread khác của bạn chỉ đơn giản gọi pthread_cond_wait mà không cần kiểm tra xem điều kiện mong muốn (counter đạt mười) đã xảy ra chưa. Đã xảy ra Tôi nghĩ biến điều kiện hoạt động như sau: khi thực thi đạt pthread_cond_wait, chuỗi bị treo cho đến khi nhận được tín hiệu. tại sao tôi phải kiểm tra thời tiết điều kiện mong muốn đã xảy ra vì đây là nhiệm vụ của biến điều kiện? tôi có nghĩa là ... tại sao tôi cần biến điều kiện kể từ khi tôi chỉ có thể làm một vòng lặp để kiểm tra nếu điều kiện của tôi là đạt và tạo ra một lá cờ cho điều này ví dụ. và khi lá cờ đó là đúng, các chủ đề khác thoát. –

+0

Tôi đã cố gắng để đặt pthread_cond_wait trong vòng lặp như bạn đã nói nhưng nó vẫn không hoạt động ... http://pastebin.com/tNB9wCMW Tôi rất bối rối vì tôi không hiểu làm thế nào bạn có thể kiểm soát chủ đề để thực hiện đạt pthread_cond_wait trước khi pthread_cond_signal Cảm ơn câu trả lời của bạn –

+0

điều gì xảy ra khi thực thi đạt pthread_cond_wait. hiện tượng này có bị đóng băng cho đến khi nhận được tín hiệu không? nếu có, tại sao tôi cần một vòng lặp while và không chỉ là một tuyên bố nếu? –

2

Tôi không biết vấn đề thực tế của bạn là gì (điều gì xảy ra khi nó không hoạt động?) ..

Tôi thấy một vấn đề lớn, bạn không xử lý spurious wakeups.

Bạn cần cái gì đó báo hiệu rằng tình trạng này thực sự đúng, ví dụ với một biến boolean:

init:

signaled = false; 

tín hiệu:

signaled = true; 
pthread_cond_signal(&cond); 

nhận:

while (!signaled) 
    pthread_cond_wait(&cond, &myMutex); 
+0

Vấn đề chính là * mất * wakeup, mà bạn cần một 'if' xung quanh' pthread_cond_wait'. Đánh thức giả mạo là một vấn đề nhỏ đòi hỏi phải là một 'while'. Nó không chắc rằng một sự thức tỉnh giả mạo thậm chí sẽ xảy ra trong tình huống một lần này chỉ với hai luồng. – Kaz

+0

yepp, tôi đã thấy câu trả lời tuyệt vời của bạn;) –

0

Đây chỉ là một ý tưởng nhưng bạn cũng có thể sử dụng semaphores để làm "kích hoạt". Tôi nhớ một dự án mà tôi đã làm trước đây và những gì chúng tôi đã làm trong khi một trong các chủ đề của chúng tôi đang chờ để được kích hoạt (sử dụng sem_wait) nó chỉ đơn giản là chờ một thời gian vô hạn cố gắng lấy khóa (và do đó đã bị gỡ bỏ các proc bởi lịch trình và tiết kiệm chu kỳ quý giá). Một khi các chủ đề chính đã được thực hiện làm tính toán của mình, nó sẽ phát hành semaphore cho phép các chủ đề thứ hai để làm điều đó tính toán.

Đây chỉ đơn giản là một giải pháp thay thế khác.

1

Điều bạn muốn là một semaphore không phải là biến điều kiện.

Một semaphore duy trì trạng thái và đếm wait() và signal() dựa vào nó.
Nó thường được thực hiện bằng cách sử dụng biến điều kiện.

Nhìn here để thực hiện tầm thường.

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