条件变量程序适用于2个线程,但不适用于3个线程

无助的流浪者

因此,我有一个程序,该程序具有2个线程,可将变量从0递增到100,并且工作正常。

#include<stdio.h>
#include<stdlib.h>
#include<semaphore.h>
#include<pthread.h>

int contor;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

void *incrementare(void *args) {
    int id = (int)args;
    while(1) {
        pthread_mutex_lock(&mutex);
        if (contor >= 100) {
            pthread_cond_signal(&cond);
            pthread_mutex_unlock(&mutex);
            pthread_exit(NULL);
        }

        while (contor %2 == id) {
        pthread_cond_wait(&cond,&mutex);
        }

        contor++;
        printf("Thread %d increment: %d\n",id,contor);


        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mutex);
    }
}

int main(void) {
    pthread_t th1, th2,th3;

    if(pthread_create(&th1, NULL, &incrementare, (void *)0) < 0) {
        perror("Error!\n");
        exit(1);
    }
    if(pthread_create(&th2, NULL, &incrementare, (void *)1) < 0) {
        perror("Error!\n");
        exit(2);
    }


    pthread_join(th1, NULL);
    pthread_join(th2, NULL);

    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);

    return 0;
}

结果是这样的:

Thread 1 increment: 1
Thread 0 increment: 2
Thread 1 increment: 3
Thread 0 increment: 4
Thread 1 increment: 5
Thread 0 incre.. and so on ,which is nice.

但是问题是当我尝试使用3个线程时,它不再起作用,因为它们随后随机出现。我只进行了3次更改,但不知道问题出在哪里。

#include<stdio.h>
#include<stdlib.h>
#include<semaphore.h>
#include<pthread.h>

int contor;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

void *incrementare(void *args) {
    int id = (int)args;
    while(1) {
        pthread_mutex_lock(&mutex);
        if (contor >= 100) {
            pthread_cond_signal(&cond);
            pthread_mutex_unlock(&mutex);
            pthread_exit(NULL);
        }

        while (contor %3 == id) {
        pthread_cond_wait(&cond,&mutex);
        }

        contor++;
        printf("Thread %d increment: %d\n",id,contor);


        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mutex);
    }
}

int main(void) {
    pthread_t th1, th2,th3;

    if(pthread_create(&th1, NULL, &incrementare, (void *)0) < 0) {
        perror("Error!\n");
        exit(1);
    }
    if(pthread_create(&th2, NULL, &incrementare, (void *)1) < 0) {
        perror("Error!\n");
        exit(2);
    }
    if(pthread_create(&th3, NULL, &incrementare, (void *)2) < 0) {
        perror("Error!\n");
        exit(3);
    }



    pthread_join(th1, NULL);
    pthread_join(th2, NULL);
        pthread_join(th3, NULL);


    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);

    return 0;
}

它应该做同样的权利吗?现在只有3个。为什么不起作用?这是这样的

Thread 2 increment: 1
Thread 2 increment: 2
Thread 1 increment: 3
Thread 1 increment: 4
Thread 2 increment: 5
Thread 1 increment: 6
WhozCraig

如果你想线程以保证循环,你需要做一个线程等待,直到模N计数器(线程数)是一个特定的ID,直到它是什么,那个特定的ID。有两个id,如果不是一个,则必须是另一个。但是对于三个,有两个中断的情况,一个等待的情况。调度程序可以自由选择要释放的两个备用线程中的任何一个。

但是,如果您更改此设置:

while (contor %3 == id)

对此:

while (contor %3 != id)

您将强制给定线程写入以其id为模的值。

但是,这还不够您还需要唤醒所有服务员。以前,当您只有两个线程时,总是有相同的服务员:不是活动线程的“另一个人”。pthread_cond_signal将被定向到特定的目标线程(唯一一个未运行的线程),并且自然也是下一个线程。

如果使用三个或更多线程,则pthread_cond_signal可能被唤醒的单线程可能不是具有扭曲模N id的线程实际上,您拥有的线程越多,发生这种情况的可能性就越大。在这种情况下,线程将返回等待状态,但没有其他等待状态会再次启动。您不想让这个碰碰运气。确保所有服务员都醒了,以确保下一个服务员能够收到信号。

千万不能仅通过发送另一个解决这个问题pthread_cond_signal的地方。而是发送广播:更改此内容:

pthread_cond_signal(&cond);

对此:

pthread_cond_broadcast(&cond);

这将确保所有正在等待的线程最终都能看清楚,contor并且与contorN模匹配的线程将有机会碰碰,打印,发送下一个广播,然后回到等待状态。

因此,对代码的最小更改是:

#include<stdio.h>
#include<stdlib.h>
#include<stdint.h>      // added for intptr_t
#include<inttypes.h>    // added for printf formatter for intptr_t
#include<pthread.h>

int contor;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

void *incrementare(void *args) {
    intptr_t id = (intptr_t)args; // proper way to pass an integer via thread param
    while(1) {
        pthread_mutex_lock(&mutex);
        if (contor >= 100) {
            pthread_cond_broadcast(&cond);
            pthread_mutex_unlock(&mutex);
            pthread_exit(NULL);
        }

        while (contor %3 != id) {
        pthread_cond_wait(&cond,&mutex);
        }

        contor++;
        printf("Thread %"PRIdPTR " increment: %d\n",id,contor);


        pthread_cond_broadcast(&cond);
        pthread_mutex_unlock(&mutex);
    }
    return NULL; // should always have well-defined return value
}

int main(void) {
    pthread_t th1, th2,th3;

    if(pthread_create(&th1, NULL, &incrementare, (void *)0) < 0) {
        perror("Error!\n");
        exit(1);
    }
    if(pthread_create(&th2, NULL, &incrementare, (void *)1) < 0) {
        perror("Error!\n");
        exit(2);
    }
    if(pthread_create(&th3, NULL, &incrementare, (void *)2) < 0) {
        perror("Error!\n");
        exit(3);
    }

    pthread_join(th1, NULL);
    pthread_join(th2, NULL);
    pthread_join(th3, NULL);

    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);

    return 0;
}

结果如下:

Thread 0 increment: 1
Thread 1 increment: 2
Thread 2 increment: 3
Thread 0 increment: 4
Thread 1 increment: 5
Thread 2 increment: 6
Thread 0 increment: 7
Thread 1 increment: 8
Thread 2 increment: 9
Thread 0 increment: 10
....
Thread 0 increment: 97
Thread 1 increment: 98
Thread 2 increment: 99
Thread 0 increment: 100
Thread 1 increment: 101
Thread 2 increment: 102

现场观看

额外的两个输出是因为代码检查的天花板休息条件是之前的CVaR的-谓词环路。应该在之后,但是我留给您解决。

但是请记住,这样做最终会破坏在任务上松开多个线程的目的。理想情况下,您希望任何可用线程来执行工作。您的工作只影响单个全局变量,这在一定程度上破坏了线程的真正目的(显然,您不会使用线程计数到100;因此,在循环中使用单个线程是理想的选择)。


无论如何,程序的压缩版本将显示在下面。更改的值N_THREADS,并N_COUNT看到输出的差异。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <pthread.h>

#define N_THREADS 7
#define N_COUNT   100

int contor;  // 0

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

void *incrementare(void *args)
{
    intptr_t id = (intptr_t)args;
    pthread_mutex_lock(&mutex);
    while(1)
    {
        while (contor < N_COUNT && contor % N_THREADS != id)
            pthread_cond_wait(&cond, &mutex);

        if (contor == N_COUNT)
            break;

        printf("Thread %"PRIdPTR" increment: %d\n", id, ++contor);
        pthread_cond_broadcast(&cond);
    }
    pthread_mutex_unlock(&mutex);
    return NULL;
}

int main(void)
{
    pthread_t ar[N_THREADS];
    intptr_t id = 0;

    for (int i=0; i<N_THREADS; ++i)
    {
        if(pthread_create(ar+i, NULL, &incrementare, (void *)id++) < 0) {
            perror("Error!\n");
            exit(1);
        }
    }

    for (int i=0; i<N_THREADS; ++i)
        pthread_join(ar[i], NULL);

    return 0;
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

测试适用于“ $ f”,但不适用于“ $ @”

来自分类Dev

重写规则适用于1-4个参数,但不适用于1个参数

来自分类Dev

Spring Transactional方法不适用于单独的线程

来自分类Dev

Python Queue的用法适用于线程处理,但(显然)不适用于多处理

来自分类Dev

非方法的eta扩展适用于字段,但不适用于局部变量

来自分类Dev

条件变量程序适用于2个线程,但不适用于3个线程

来自分类Dev

锁定方法仅适用于2个线程

来自分类Dev

Keras不适用于3个或更多的尺寸。InvalidArgumentError

来自分类Dev

.pgpass适用于一个用户,但不适用于postgres用户

来自分类Dev

多线程C程序不适用于Args

来自分类Dev

括号扩展不适用于少于2个参数

来自分类Dev

重写规则适用于1-4个参数,但不适用于1个参数

来自分类Dev

scrollTop不适用于2个运算符

来自分类Dev

线程不适用于多个连接

来自分类Dev

MPI代码不适用于2个节点,但适用于1个节点

来自分类Dev

注册功能适用于一个脚本,但不适用于另一个脚本

来自分类Dev

方法适用于文字值,但不适用于具有相同值的变量

来自分类Dev

wp 条件适用于 php 7 但不适用于 php 5

来自分类Dev

制作了一个适用于 JSFiddle 但不适用于 Github Pages 的 etch-a-sketch

来自分类Dev

Jquery 函数适用于表的第一个 td,但不适用于克隆

来自分类Dev

.bat 文件适用于两个域系统,但不适用于其他系统

来自分类Dev

Chrome 仅适用于 1 个帐户,但不适用于其他 3 个帐户

来自分类Dev

Spark Sql 查询适用于硬编码值但不适用于变量

来自分类Dev

Elasticsearch 在 must 中适用于一个术语,但不适用于两个

来自分类Dev

命名空间适用于一个类,但不适用于其他类

来自分类Dev

Fragment 接口/侦听器适用于 Activity,但不适用于另一个 Fragment

来自分类Dev

适用于 PHP 但不适用于脚本

来自分类Dev

相同的连接文件适用于 1 个脚本,但不适用于另一个

来自分类Dev

代码适用于静态 PHP 值,但不适用于动态变量

Related 相关文章

  1. 1

    测试适用于“ $ f”,但不适用于“ $ @”

  2. 2

    重写规则适用于1-4个参数,但不适用于1个参数

  3. 3

    Spring Transactional方法不适用于单独的线程

  4. 4

    Python Queue的用法适用于线程处理,但(显然)不适用于多处理

  5. 5

    非方法的eta扩展适用于字段,但不适用于局部变量

  6. 6

    条件变量程序适用于2个线程,但不适用于3个线程

  7. 7

    锁定方法仅适用于2个线程

  8. 8

    Keras不适用于3个或更多的尺寸。InvalidArgumentError

  9. 9

    .pgpass适用于一个用户,但不适用于postgres用户

  10. 10

    多线程C程序不适用于Args

  11. 11

    括号扩展不适用于少于2个参数

  12. 12

    重写规则适用于1-4个参数,但不适用于1个参数

  13. 13

    scrollTop不适用于2个运算符

  14. 14

    线程不适用于多个连接

  15. 15

    MPI代码不适用于2个节点,但适用于1个节点

  16. 16

    注册功能适用于一个脚本,但不适用于另一个脚本

  17. 17

    方法适用于文字值,但不适用于具有相同值的变量

  18. 18

    wp 条件适用于 php 7 但不适用于 php 5

  19. 19

    制作了一个适用于 JSFiddle 但不适用于 Github Pages 的 etch-a-sketch

  20. 20

    Jquery 函数适用于表的第一个 td,但不适用于克隆

  21. 21

    .bat 文件适用于两个域系统,但不适用于其他系统

  22. 22

    Chrome 仅适用于 1 个帐户,但不适用于其他 3 个帐户

  23. 23

    Spark Sql 查询适用于硬编码值但不适用于变量

  24. 24

    Elasticsearch 在 must 中适用于一个术语,但不适用于两个

  25. 25

    命名空间适用于一个类,但不适用于其他类

  26. 26

    Fragment 接口/侦听器适用于 Activity,但不适用于另一个 Fragment

  27. 27

    适用于 PHP 但不适用于脚本

  28. 28

    相同的连接文件适用于 1 个脚本,但不适用于另一个

  29. 29

    代码适用于静态 PHP 值,但不适用于动态变量

热门标签

归档