2014-09-12 126 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