2012-03-05 2 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 

문제는 단지 하나의 스레드가 만들어지고 있다는 것이다! 함수를 메인()에서 4 번, 다른 serverID에서 2 번 호출하여 두 개의 스레드를 생성해야합니까?

무엇이 누락 되었습니까? 이 동작에 기여하는 경우

+1

C 헤더가 아닌 C++ 헤더를 사용하십시오. 'stdio.h '가 아니라'cstdio'입니다. –

+0

또한 도구 모음에서 제공하는 경우'boost :: thread' 또는'std :: thread'를 살펴볼 수도 있습니다. – ereOn

+0

@ereOn 현재 pthreads에 대해서만 배우고 있으므로, 그들에게만 집중하고 싶습니다. 감사합니다. –

답변

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)) 

편집 :

나는이 문제입니다 생각 :

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

: checkServerExists()가 호출 될 때, 그것을 완료하기 시작하는 스레드를 기다리는 것 같다 즉 스레드 ID 140233482061584은 더 이상 사용 중이 지 않으며 다시 새 스레드와 연결될 수 있습니다. checkServerExists()에 대한 다음 호출이 이루어지면 스레드 ID가 재사용되어 하나의 스레드 만 시작되었다는 인상을줍니다.

편집 2 :

이것은 잘못된 바르 지적 :

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

는 두 pthread_t을 비교 pthread_equal()를 사용해야합니다. 로 변경

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

또는 다른 스레드에 대한 인수로 serverId을 전달합니다.

+0

나는 그것을 시도, 문제를 해결하지 않습니다. 그러나 여전히 - 좋은 지적입니다. –

+1

편집의 요점은 거의 확실하게 중요한 포인트입니다. 그리고 @hmjd가 나타내는 것조차 더 나쁜 것입니다; 스레드를 사용하려는 추가 시도는 종료 될 것이므로 no-ops가됩니다. –

+0

hmjd, @JamesKanze 어떻게 안전하게 가입 할 수 있습니까? –

2

EDITED : 실제 문제는 스레드가 종료되고 곧 hmjd가 가리키는 것처럼 으로 조인된다는 것입니다. 나는 다음과 같은 문제가 있기 때문에 이것을 삭제하지 않고 으로 남겨 두었습니다.

내가 게시 한 출력에 새 스레드가 두 개 생성되었습니다. "In checkServerExists"은 새 스레드를 생성 한 경우에만 출력됩니다. 시스템이되고 싶어, 당신은에 전달하는 형식으로 필요한 것입니다 long 이외의 가능성이 뭔가를, 아무것도 할 수있다 pthread_t을 입력 한 newThread : 나는 또한 는 printf에 정의되지 않은 동작을 볼 printf. 내가 아는 한, 은 (이동 가능하게) pthread_t ( 바이트의 16 진수 덤프 이외)을 출력하지 않습니다. 스레드 ID로 표시 한 값은 아무 의미도 없습니다. 또한 ==을 사용하여 pthread_t을 비교할 수 없으므로 pthread_equal을 사용해야합니다.(내가 사용한 적어도 하나의 플랫폼에서 pthread_tstruct입니다.)

코드에 다른 이상한 점이 많이 있습니다. 예를 들어 bool이 아닌 foundchar 유형으로 선언하는 이유는 무엇입니까? 그리고 왜 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

+0

그런 다음 threadId를 인쇄하는 방법은 무엇입니까? –

+0

'이유는 무엇입니까? 루프에서'i의 값을 인덱스 값으로 사용합니다. –

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

+0

@CashCow 단어는 "he"가 아니라 "she"이어야합니다. –

+0

문자열 비교가 컴파일러 오류가 아닌 것처럼 컴파일러 오류가 아닙니다. 지정된 thread가 1 개뿐의 유효한 thread ID 표현을 가진다는 보장이 없기 때문에 의미 론적 의미가 없다. –

0

나는 이유를 볼 수 있습니다 기대했던대로 작동하지 않습니다. 서버 측에서는 main에서 전달 된 고유 식별자를 사용하여 해당 스레드 ID가 무엇인지 결정하지만 스레드 함수 자체는 스레드 ID를 사용합니다.

작성한 첫 번째 작업자 스레드가 종료되었습니다. 두 번째 작업자 스레드는 현재 ID를 사용할 수 있으므로 첫 번째 작업자 스레드와 동일한 ID로 생성됩니다.

주 스레드가 문자열을 벡터의 두 번째 요소 큐에 넣고 있지만 스레드가 일치하는 스레드 ID를 가지고 있기 때문에 벡터의 첫 번째 요소를 선택하고 있습니다.

이전 포스터에서 말한 모든 것들도 역시 고려해야합니다. 단지 당신의 행동을 일으키는 사람이 아니라는 것입니다. 스레드를 처리하는 동안 당신이 연속적으로와 push_back을 할 경우

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

    // look through the queue 
} 

변경 std::list 또는 std::deque에 수집 유형은 그래서 포인터를 무효화하지 않습니다.

checkServerExists에서 serverInfo의 주소를 thread_id의 주소가 아닌 스레드 함수에 전달하십시오.

int를 serverInfo *로 매핑하거나 목록을 사용하는 경우 목록 반복기에지도를 "색인"할 수도 있습니다. std::map<int, serverInfo>을 사용하면 안됩니다.지도에 새 항목을 추가하면 포인터가 무효화 될 수 있기 때문입니다.

덧붙여 말하자면, 작업자 스레드가 너무 일찍 종료 된 것처럼 보일 수 있습니다. 왜냐하면 이후 정보를 이전 ID로 보내면 스레드가 이미 사라 졌기 때문입니다.

대기열이 비어있는 것은 스레드를 종료 할 조건이 아니어야하며 다른 방법을 사용해야합니다.

덧붙여 말하자면 thread-safe 한 동안 뮤텍스는 너무 길게 잠겨 있기 때문에 여기서 여러 스레드를 사용하여 성능을 향상시키지 않을 것입니다.

관련 문제