繁体   English   中英

多线程

[英]Multithreading

我刚开始学习多线程。 我写了一个简单的应用程序。 应用程序创建三个线程。 两个线程写入,一个线程读取。 编写器线程写入全局数组中的单独位置。 增加数组中的值后的写入器线程通知读取器。 读取器线程然后递减数组中的值并再次等待写入器线程更新它们在数组中的对应值。 该应用程序的代码粘贴在下面。

我看到的是作者(生产者)线程比读者(消费者)线程获得更多的时间片。 我想我做错了什么。 如果应用程序的output被重定向到一个文件,那么可以观察到来自Producers的连续消息较多,来自Consumer的消息很少出现。 我所期望的是,当生产者更新其数据时,消费者会立即处理它,即在每条生产者消息之后应该打印一条消费者消息。

谢谢并恭祝安康,

~插头

#include <stdio.h>

#include <pthread.h>

const long g_lProducerCount = 2; /*Number of Producers*/

long g_lProducerIds[2]; /*Producer IDs = 0, 1...*/
long g_lDataArray[2]; /*Data[0] for Producer 0, Data[1] for Producer 1...*/

/*Producer ID that updated the Data. -1 = No update*/
long g_lChangedProducerId = -1;

pthread_cond_t g_CondVar = PTHREAD_COND_INITIALIZER;
pthread_mutex_t g_Mutex  = PTHREAD_MUTEX_INITIALIZER;
pthread_t g_iThreadIds[3]; /*3 = 2 Producers + 1 Consumer*/

unsigned char g_bExit = 0; /*Exit application? 0 = No*/

void* Producer(void *pvData)
{
    long lProducerId = *(long*)pvData; /*ID of this Producer*/

    while(0 == g_bExit) {
        pthread_mutex_lock(&g_Mutex);

        /*Tell the Consumer who's Data is updated*/
        g_lChangedProducerId = lProducerId;

        /*Update the Data i.e. Increment*/
        ++g_lDataArray[lProducerId];

        printf("Producer: Data[%ld] = %ld\n",
                lProducerId, g_lDataArray[lProducerId]);

        pthread_cond_signal(&g_CondVar);
        pthread_mutex_unlock(&g_Mutex);
    }

    pthread_exit(NULL);
}

void* Consumer(void *pvData)
{
    while(0 == g_bExit) {
        pthread_mutex_lock(&g_Mutex);

        /*Wait until one of the Producers update it's Data*/
        while(-1 == g_lChangedProducerId) {
            pthread_cond_wait(&g_CondVar, &g_Mutex);
        }

        /*Revert the update done by the Producer*/
        --g_lDataArray[g_lChangedProducerId];

        printf("Consumer: Data[%ld] = %ld\n",
                g_lChangedProducerId, g_lDataArray[g_lChangedProducerId]);

        g_lChangedProducerId = -1; /*Reset for next update*/

        pthread_mutex_unlock(&g_Mutex);
    }

    pthread_exit(NULL);
}

void CreateProducers()
{
    long i;

    pthread_attr_t attr;
    pthread_attr_init(&attr);

    for(i = 0; i < g_lProducerCount; ++i) {
        g_lProducerIds[i] = i;
        pthread_create(&g_iThreadIds[i + 1], &attr,
                        Producer, &g_lProducerIds[i]);
    }

    pthread_attr_destroy(&attr);
}

void CreateConsumer()
{
    pthread_attr_t attr;
    pthread_attr_init(&attr);

    pthread_create(&g_iThreadIds[0], &attr, Consumer, NULL);

    pthread_attr_destroy(&attr);
}

void WaitCompletion()
{
    long i;
    for(i = 0; i < g_lProducerCount + 1; ++i) {
        pthread_join(g_iThreadIds[i], NULL);
    }
}

int main()
{
    CreateProducers();
    CreateConsumer();

    getchar();

    g_bExit = 1;

    WaitCompletion();

    return 0;
}

您必须澄清您想要达到的目标。 现在生产者只增加一个 integer 并且消费者减少这个值。 这不是一个非常有用的活动;)我知道这只是一个测试应用程序,但仍然不够清楚这个处理的目的是什么,有什么限制等等。

生产者生产一些“物品”。 此生成的结果表示为 integer 值。 0 表示没有物品,1 表示有待处理的物品,消费者可以拿走。 那正确吗? 现在,生产者是否可以在其中任何一个被消耗之前生产多个项目(将数组单元格增加到大于 1 的值)? 还是他必须等到最后一件物品被消耗完才能将下一件物品放入仓库? 存储空间是有限的还是无限的? 如果它是有限的,那么限制是在所有生产者之间共享还是每个生产者都定义?

我所期望的是,当生产者更新其数据时,消费者会立即处理它,即在每条生产者消息之后应该打印一条消费者消息。

虽然不清楚您想要实现什么,但我将坚持该报价并假设以下内容:每个生产者限制为 1 个项目,并且生产者必须等待消费者清空存储空间,然后才能获得新项目放入单元格中,即 g_lDataArray 中唯一允许的值是 0 和 1。

为了允许线程之间的最大并发性,您需要为 g_lDataArray 的每个单元格(每个生产者)设置一个条件变量/互斥锁对。 您还需要一个更新队列,即已提交工作的生产者列表和一个条件变量/互斥锁对来保护它,这将替换 g_lChangedProducerId,它一次只能保存一个值。

每次生产者想要将项目放入存储时,它必须获取相应的锁,检查存储是否为空(g_lDataArray[lProducerId] == 0),如果不等待条件变量,然后增加单元格,释放持有的锁,获取消费者锁,将自己的id加入更新队列,通知消费者,释放消费者锁。 当然,如果生产者将执行任何实际计算来生成一些真实项目,则应在尝试将项目放入存储之前,在任何锁的 scope 之外执行这项工作。

在伪代码中,它看起来像这样:

// do some computations
item = compute();

lock (mutexes[producerId]) {
    while (storage[producerId] != 0)
        wait(condVars[producerId]);
    storage[producerId] = item;
}

lock (consumerMutex) {
    queue.push(producerId);
    signal(consumerCondVar);
}        

消费者应该采取如下行动:获取他的锁,检查是否有待处理的更新,如果没有等待条件变量,则从队列中取出一个更新(即更新生产者的编号),获取锁对于要处理更新的生产者,递减单元格,通知生产者,释放生产者的锁,释放他的锁,最后处理更新。

lock (consumerMutex) {
    while (queue.isEmpty())
        wait(consumerCondVar);
    producerId = queue.pop();
    lock (mutexex[producerId]) {
        item = storage[producerId];
        storage[producerId] = 0;
        signal(condVars[producerId]);
    }
}

//process the update
process(item);

希望这个答案是您所需要的。

好吧,当你生产者生产时,它可能会唤醒 ProThread 或 ConThread。 而如果它唤醒了ProThread,Producer又生产了,ConThread并没有在数据产生后立即消费。 那是你不想看到的。 您需要做的就是确保它在生成时不会唤醒 ProThread。 这是一种解决方案

    void* Producer(void *pvData)
    {
            ........
            //wait untill consumer consume its number
            while(-1!=g_lChangedProducerId)
                    pthread_cond_wait(&g_CondVar,&g_Mutex);
            //here to inform the consumer it produced the data
            g_lChangedProducerId = lProducerId;
            ........
    }

    void* Consumer(void *pvData)
    {
            g_lChangedProducerId = -1;
            **//wake up the producer when it consume
            pthread_cond_signal(&g_CondVar);**
            pthread_mutex_unlock(&g_Mutex);
    }

问题可能是所有生产者都改变了g_lChangedProducerId,所以一个生产者写入的值可能在消费者看到之前就被另一个生产者覆盖了。

这意味着消费者实际上没有看到第一个生产者生产了一些 output。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM