2012-03-05 45 views
0
#include <pthread.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <vector> 
#include <string> 
#include <iostream> 

FILE*   fp; 
pthread_mutex_t demoMutex   = PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t conditionVariable = PTHREAD_COND_INITIALIZER; 
unsigned int condition   = 0; 

struct serverInfo 
{ 
    unsigned int serverId; 
    pthread_t threadId; 
    std::vector<std::string> queue; 
}; 
std::vector<serverInfo> serverInfoVector; 

void* printHello(void* threadId) 
{ 
    pthread_t* my_tid = (pthread_t*)threadId; 

    pthread_mutex_lock(&demoMutex); 
    while (condition == 0) 
     pthread_cond_wait(&conditionVariable, &demoMutex); 

    unsigned int i = 0; 
    char found = false; 

    if (serverInfoVector.size() > 0) { 
     while ((i <= serverInfoVector.size()) && (found == false)) { 
      if (*my_tid == serverInfoVector[i].threadId) { 
      found = true; 
      break; 
      } 
      else 
      i++; 
     } 
    } 

    while (!serverInfoVector[i].queue.empty()) { 
     std::cout << "\nThread: " << pthread_self() << ", poped from queue: " << serverInfoVector[i].queue.front(); 
     serverInfoVector[i].queue.pop_back(); 
    } 

    pthread_mutex_unlock(&demoMutex); 
    pthread_exit(NULL); 
} 

void checkServerExists(unsigned int serverNumber, std::string message) 
{ 
    unsigned int i = 0; 
    char found = false; 

    pthread_mutex_lock(&demoMutex); 

    if (serverInfoVector.size() > 0) { 
     while ((i <= serverInfoVector.size()) && (found == false)) { 
      if (serverNumber == serverInfoVector[i].serverId) { 
      found = true; 
      break; 
      } 
      else 
      i++; 
     } 
    } 

    if (found == false) { 
     // This server doesn't exist, so create a thread for it, create a queue for it, push the message in the corresponding queue. 
     // Push the server number in the serverNumberArray. 

     // Create a thread for it. 
     pthread_t newThread; 
     int returnValue; 
     if ((returnValue = pthread_create (&newThread, NULL, printHello, (void*) &newThread)) != 0) { 
      printf("\nerror: pthread_create failed with error number %d", returnValue); 
     } 
     printf("\nIn checkServerExists()`: thread id %ld\n", newThread); 

     // Push the message in its queue. 
     serverInfo obj; 
     obj.serverId = serverNumber; 
     obj.threadId = newThread; 
     obj.queue.push_back(message); 
     serverInfoVector.push_back(obj); 

     condition++; 
     pthread_cond_signal(&conditionVariable); 
     pthread_mutex_unlock(&demoMutex); 

     for (unsigned int i = 0; i < serverInfoVector.size(); i++) 
      pthread_join(serverInfoVector[i].threadId, NULL); 
    } 
    else { 
     // This server exists, so lookup its thread and queue, push the message in the corresponding queue. 
     printf("\nIn else()`: thread id %ld\n", serverInfoVector[i].threadId); 
     serverInfoVector[i].queue.push_back(message); 

     condition++; 
     pthread_cond_signal(&conditionVariable); 
     pthread_mutex_unlock(&demoMutex); 

     for (unsigned int i = 0; i < serverInfoVector.size(); i++) 
      pthread_join(serverInfoVector[i].threadId, NULL); 
    } 
} 

int main() 
{ 
    fp = fopen("xyz", "w"); 

    checkServerExists(1, "anisha"); 
    checkServerExists(2, "kaul"); 
    checkServerExists(1, "sanjeev"); 
    checkServerExists(2, "sharma"); 
} 

輸出:只有一個線程得到儘管嘗試創建創建兩個

In checkServerExists()`: thread id 140233482061584 

Thread: 140233482061584, poped from queue: anisha 
In checkServerExists()`: thread id 140233482061584 

In else()`: thread id 140233482061584 

In else()`: thread id 140233482061584 

的問題是,它似乎是越來越只創建一個線程!我已經在main()中調用了函數checkServerExists 4次,並且使用不同的serverID調用了2次,所以應該創建兩個線程?

我錯過了什麼?

+1

使用C++頭文件,而不是C頭文件。 'cstdio',而不是'stdio.h'。 – 2012-03-05 09:59:46

+0

另外,如果你的工具鏈提供了'boost :: thread'或甚至'std :: thread',你可能會想看看。 – ereOn 2012-03-05 10:06:43

+0

@ereOn目前我只學習pthreads,所以只想集中它們,謝謝。 – 2012-03-05 10:07:56

回答

1

我不能確定這是否有助於行爲,但下面是一個錯誤:

while ((i <= serverInfoVector.size()) && (found == false)) 
{ 
    if (serverNumber == serverInfoVector [i].serverId) 
    { 
     found = true; 
     break; 
    } 
    else 
     i++; 
} 

serverInfoVector[i]將訪問一個太多由於if<=條件。更改爲:

while ((i < serverInfoVector.size()) && (found == false)) 

編輯:

認爲這就是問題所在:當checkServerExists()被調用時,它似乎等待線程,它開始完成:

for (unsigned int i = 0; i < serverInfoVector.size(); i++) 
    pthread_join(serverInfoVector[i].threadId, NULL); 

這意味着,線程ID 140233482061584不再使用,可再次用一個新的線程關聯。何時checkServerExists()下次調用由線程ID可重複使用,讓只有一個線程啓動的印象。

編輯2:

正如施瓦茲指出,這是不正確的:

if (*my_tid == serverInfoVector[i].threadId) { 

你需要使用pthread_equal()比較兩個pthread_t。更改爲:

if (pthread_equal(*my_tid, serverInfoVector[i].threadId)) { 

或可替代地通過serverId作爲參數給線程。

+0

我試過了,沒有解決問題。但仍然 - 好點。 – 2012-03-05 10:06:11

+1

編輯中的要點幾乎肯定是關鍵點。 @hmjd表示更糟的是;進一步嘗試使用該線程將是空操作,因爲它已經終止。 – 2012-03-05 10:20:10

+0

hmjd和@JamesKanze如何安全地加入,在你看來? – 2012-03-05 10:20:35

2

EDITED:真正的問題是線程終止並在創建完成後立即連接爲 ,正如hmjd指出的那樣。我離開這個, 而不是刪除它,因爲以下也是問題。

我看到在輸出你後一個新的線程兩個作品:"In checkServerExists"僅輸出,如果你創建一個新的線程。我也 看到printf未定義行爲:newThread已鍵入 pthread_t,它可以是任何系統希望它是,並且是 比long其他可能的事情,這是由你傳遞給 格式要求printf。還有就是,據我所知,沒有辦法的(便攜) (比其 字節的十六進制轉儲等)輸出pthread_t;您顯示爲線程ID的值並不代表任何內容。 另外,還可以使用==比不上pthread_t,你需要使用 pthread_equal。(在我使用的至少一個平臺上,pthread_tstruct。)

您的代碼還有其他許多奇怪的事情。例如,爲什麼要聲明 found,其類型爲char,而不是類型bool。以及爲什麼 found == false,而不是!found。以及爲什麼break;在 循環中,因爲您在循環控制變量中有條件。的checkServerExists開始的多 更地道的形式是:

for (std::vector<ServerInfo>::iterator current = serverInfoVector.begin(); 
     current != serverInfoVector.end() && current->serverId != serverNumber; 
     ++ current) { 
} 
if (current == serverInfoVector.end()) { 
    // not found... 
} else { 
    // found... 
} 

假設您沒有創建查找一個predicte對象,只是 使用std::find

+0

+1沒有注意到''printf()'和'pthread_t'的濫用,這可能會導致我的解釋失效。 – hmjd 2012-03-05 10:20:04

+0

那麼打印threadId的方法是什麼? – 2012-03-06 06:07:28

+0

'爲什麼休息;在循環中,'保存'i'的值作爲索引值。 – 2012-03-06 06:11:17

1
 if (*my_tid == serverInfoVector[i].threadId) { 

你不能比較pthread_t那樣。這是一個C接口,而不是C++接口。所以沒有運營商超載,使這種比較工作明智。這是錯誤的,這是錯誤的:

const char *foo="foo"; 
    if(foo == "foo") ... 

你必須使用一個合理的比較函數。在我的例子中,strcmp。在你的代碼中,pthread_equal

此外,您pthread_join一個線程後,其pthread_t不再有效。您不能再次將它傳遞給任何pthread_*函數。這與將指針傳遞到free後解引用指針一樣糟糕。

(您可能需要修正一些都在這個線程錯誤報告,併發布了新的問題,並提供更新的代碼以及任何問題的說明你還有用它。)

+0

問題不在於他如何比較線程ID。 (如果他不能以這種方式比較它們將會是編譯器錯誤)。問題是他根本不應該比較它們。 – CashCow 2012-03-05 10:34:05

+0

@CashCow這個詞應該是「她」而不是「他」。 – 2012-03-05 10:35:13

+0

這不是編譯器錯誤,就像字符串比較不是編譯器錯誤。它只是沒有語義意義,因爲不能保證給定的線程只有一個有效的線程ID表示。 – 2012-03-05 10:52:02

0

我可以看到,爲什麼它沒有按照你期望的方式工作。您的服務器端正在使用從main傳入的唯一標識符來確定它的線程ID應該是什麼,但線程函數本身正在使用線程ID。

第一個工人線程您創建的結束,而第二個被用相同的ID創建的第一個,因爲這個ID是現在可用。

主線程把字符串到向量中的第二個元素的隊列,但你的線程拿起向量的第一個元素,因爲它有一個匹配的線程ID。

所有他們以前的海報說的東西也應該考慮,順便說一句。只是這不是那些產生你的行爲的東西。

void* printHello(void* serverptr) 
{ 
    serverInfo * info = static_cast< serverInfo * >(serverptr); 

    // look through the queue 
} 

改變集合類型std::liststd::deque所以如果你以後做的push_back,而線程正在處理它,它也不會無效指針。

checkServerExists,通過serverInfo的地址到線程函數,而不是的thread_id的地址。

你可能還「指數」您的收藏與從int到serverInfo *或列表迭代的地圖,如果你使用的列表。您不應該使用std::map<int, serverInfo>,因爲如果您將新條目添加到地圖,它可能會使指針失效。

順便說一句,您的工作線程似乎過早終止,因爲當您將稍後的信息發送給舊的ID時,線程已經消失。

空隊列不應該是終止線程的條件,你應該使用其他方法。順便說一句,雖然它是線程安全的,但您的互斥鎖鎖定了很長時間,以至於您在這裏使用多線程並不能取得任何體面的性能。