2014-09-12 129 views
1

我已經創建了一個隊列頭文件,並試圖將它與線程一起使用。 我在做的是製作2個線程,1用於從代碼文件中讀取字符並將字符輸入到隊列中,另一個線程正在嘗試將字符打印到控制檯。 問題是沒有字符正在打印到控制檯,我無法弄清楚爲什麼。線程無法正常工作 - C

queue.h:

#ifndef QUEUE_INT 
#define QUEUE_INT 

#include <stdio.h> 
#include <stdlib.h> 
#include <stdbool.h> 

typedef struct 
{ 
    int *elementData; 
    unsigned int queueSize; 
    unsigned int capacityIncrement; 
    unsigned int elementCount; 
} Queue; 

void queue_initialize(Queue*, unsigned int); 
int queue_add(Queue*, int); 
void queue_poll(Queue*); 
int queue_peek(const Queue*); 
void queue_destroy(Queue*); 
bool queue_isEmpty(const Queue*); 
void queue_setCapacityIncrement(Queue*, unsigned int); 
unsigned int queue_getCapacityIncrement(const Queue*); 
unsigned int queue_getNumberOfElements(const Queue*); 
unsigned int queue_getSize(const Queue*); 

void queue_initialize(Queue *p, unsigned int capacityIncrement) 
{ 
    p->elementData = NULL; 
    p->queueSize = 0; 
    p->capacityIncrement = capacityIncrement; 
    p->elementCount = 0; 
} 

int queue_add(Queue *p, int value) 
{ 
    if(p->elementCount == p->queueSize) 
    { 
     int newQueueSize = p->queueSize + p->capacityIncrement; 
     void *temp = realloc(p->elementData, sizeof(*p->elementData) * newQueueSize); 
     if(temp == NULL || newQueueSize == 0) 
     { 
      return 1; 
     } 
     p->queueSize = newQueueSize; 
     p->elementData = temp; 
    } 
    p->elementData[p->elementCount] = value; 
    p->elementCount++; 
    return 0; 
} 

void queue_poll(Queue *p) 
{ 
    if(!queue_isEmpty(p)) 
    { 
     p->elementCount--; 
     if(p->queueSize - p->elementCount == p->capacityIncrement/2 + p->capacityIncrement) 
     { 
      int newQueueSize = p->queueSize - p->capacityIncrement; 
      p->elementData = realloc(p->elementData, sizeof(*p->elementData) * newQueueSize); 
      p->queueSize = newQueueSize; 
     } 
     for(int i = 0; i < p->elementCount; i++) 
     { 
      p->elementData[i] = p->elementData[i + 1]; 
     } 
    } 
} 

int queue_peek(const Queue *p) 
{ 
    if(!queue_isEmpty(p)) 
    { 
     return p->elementData[0]; 
    } 
    return 0; 
} 

void queue_destroy(Queue *p) 
{ 
    free(p); 
} 

bool queue_isEmpty(const Queue *p) 
{ 
    return p->elementCount == 0; 
} 

void queue_setCapacityIncrement(Queue *p, unsigned int capacityIncrement) 
{ 
    p->capacityIncrement = capacityIncrement; 
} 

unsigned int queue_getCapacityIncrement(const Queue *p) 
{ 
    return p->capacityIncrement; 
} 

unsigned int queue_getNumberOfElements(const Queue *p) 
{ 
    return p->elementCount; 
} 

unsigned int queue_getSize(const Queue *p) 
{ 
    return p->queueSize; 
} 

#endif 

代碼文件:

#include <stdio.h> 
#include <stdlib.h> 
#include <windows.h> 
#include <process.h> 
#include <time.h> 
#include "queue.h" 

bool isFillQueueThreadRunning; 
bool isQueueProcessing; 

void fillQueueThread(void*); 
void popQueueThread(void*); 

int main() 
{ 
    srand(time(NULL)); 
    Queue q1; 
    queue_initialize(&q1, 4); 
    HANDLE hFillQueueThread = (HANDLE)_beginthread(fillQueueThread, 0, (void*)&q1); 
    HANDLE hPopQueueThread = (HANDLE)_beginthread(fillQueueThread, 0, (void*)&q1); 
    WaitForSingleObject(hFillQueueThread, 1000 * 300); 
    WaitForSingleObject(hPopQueueThread, 1000 * 300); 
    return 0; 
} 

void fillQueueThread(void *p) 
{ 
    isFillQueueThreadRunning = true; 
    Queue *q = (Queue*)p; 
    FILE *f = fopen(__FILE__, "r"); 
    int b; 
    while((b = getc(f)) != EOF) 
    { 
     Sleep(rand() % 50); 
     while(isQueueProcessing) 
     { 

     } 
     isQueueProcessing = true; 
     if (queue_add(q, b) == 1) 
     { 
      break; 
     } 
     isQueueProcessing = false; 
    } 

    fclose(f); 
    isFillQueueThreadRunning = false; 
} 

void popQueueThread(void *p) 
{ 
    Queue *q = (Queue*)p; 
    Sleep(10); 
    int b; 
    while(isFillQueueThreadRunning || q->elementCount > 0) 
    { 
     while(isQueueProcessing) 
     { 

     } 
     isQueueProcessing = true; 
     b = queue_peek(q); 
     queue_poll(q); 
     putchar(b); 
     isQueueProcessing = false; 
    } 
} 
+2

你'_beginthread'' fillQueueThread'兩次。 – 2014-09-12 21:24:09

+0

在調試器中運行您的代碼。首先逐行執行一個線程代碼,然後逐步執行其他線程代碼。這樣做,你應該很容易找到問題所在。 – 2014-09-12 21:26:44

+0

你也有一個競賽條件。未初始化的全局變量將被初始化爲零,這意味着兩個線程都首先競爭設置「isQueueProcessing」。 – 2014-09-12 21:29:04

回答

0

_beginthreadfillQueueThread兩次。

你永遠不會初始化isFillQueueThreadRunning可靠。代碼可能取決於未初始化的變量。

從我看到的

+0

感謝您注意這些事情。關於無法正確初始化isFillQueueThreadRunning,即使我正在睡覺,它是否會影響某些內容(10);在popThread?所以我讓fillThread時間來初始化它。在解決這些問題而不是很好地打印代碼之後,在字符之間會有很多空間,有時候字符可以像兩行一樣打印出來,我不明白爲什麼會發生這種情況? – Akes55 2014-09-12 21:47:59

+0

睡眠()從來沒有修復競爭條件,它只會讓他們更難找到:( – 2014-09-13 05:06:51

+0

@JeremyFriesner如果不是在popQueueThread中的睡眠而是我會做(while isFillQueueRunning){}? – Akes55 2014-09-13 11:42:14

0

您的隊列實現遠離線程安全。正如約阿希姆所說,請用線程同步原語來自學。一個簡單的互斥體在這裏會走很長的路。

請參見:What is a mutex?

至於你的大空間塊,您使用queue_peek的輸出()無條件地,可以(並且常常)是NULL。

你知道putchar(NULL)的結果是?

+0

我已經把我的putchar if語句,如果之間(B!= 0),還是其結果是試圖把它們打印時字符缺失。關於mutex,我明白它是什麼,在我的代碼中它基本上是isQueueProcessing變量,所以我沒有看到它有什麼問題? – Akes55 2014-09-13 12:06:35

+0

queue_add()和queue_poll()都依賴於隊列狀態變量爲所述方法的持續時間是不變的,當它們不是。你爲什麼避免使用互斥鎖? – Rich 2014-09-15 21:23:00

+0

既然你似乎是使用Windows,我會推薦這: http://msdn.microsoft.com/en-us/library/windows/desktop/ms686927%28v=vs.85%29.aspx – Rich 2014-09-19 04:38:26