POSIX C 线程。 pthread_cond_t 示例。没有达到预期效果

问题描述 投票:0回答:4

我写了一个程序,但它没有按我的预期工作。 我有两个线程:

thread
触发
func
anotherThread
触发
anotherFunc
。我想做的是当
cont
达到
10
中的值
func
时,使用
anotherThread
pthread_cond_wait
触发
pthread_cond_signal
。奇怪的是,如果我取消注释
sleep(1)
行,一切都会正常。我是线程新手,我正在遵循教程here,如果我评论示例中的
sleep
行,它也会中断。

我的问题是如何在没有任何

sleep()
调用的情况下完成这项工作?如果在我的代码中,
func
pthread_mutex_lock
之后到达
anotherFunc
,会发生什么?我怎样才能控制这些事情?这是我的代码:

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

pthread_mutex_t myMutex;
pthread_cond_t cond;
pthread_attr_t attr;

int cont;

void *func(void*)
{
    printf("func\n");

    for(int i = 0; i < 20; i++)
    {
        pthread_mutex_lock(&myMutex);

        cont++;
        printf("%d\n", cont);
        if(cont == 10)
        {
            printf("signal:\n");
            pthread_cond_signal(&cond);
//            sleep(1);
        }
        pthread_mutex_unlock(&myMutex);
    }
    printf("Done func\n");

    pthread_exit(NULL);
}

void *anotherFunc(void*)
{
    printf("anotherFunc\n");
    pthread_mutex_lock(&myMutex);
    printf("waiting...\n");

    pthread_cond_wait(&cond, &myMutex);
    cont += 10;
    printf("slot\n");

    pthread_mutex_unlock(&myMutex);
    printf("mutex unlocked anotherFunc\n");
    printf("Done anotherFunc\n");

    pthread_exit(NULL);
}

int main(int argc, char *argv[])
{
    pthread_t thread;
    pthread_t anotherThread;

    pthread_attr_init(&attr);
    pthread_mutex_init(&myMutex, NULL);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
    pthread_cond_init(&cond, NULL);

    pthread_create(&anotherThread, &attr, anotherFunc, NULL);
    pthread_create(&thread, &attr, func, NULL);

    pthread_join(thread, NULL);
    pthread_join(anotherThread, NULL);

    printf("Done MAIN()");

    pthread_mutex_destroy(&myMutex);
    pthread_cond_destroy(&cond);
    pthread_attr_destroy(&attr);


    pthread_exit(NULL);
    return 0;
}

很抱歉这篇文章很长,但我是线程新手,我愿意学习。 我想学习创建一个聊天客户端,我听说我必须了解线程和网络。问题是我什至不知道我学到的东西是否可以 - 因为我不知道我必须知道什么。

非常感谢你:)

c++ multithreading pthreads conditional-variable
4个回答
10
投票

您的

anotherThread
只是调用
pthread_cond_wait
,而不首先测试所需的条件(计数器达到十)是否已经发生。这是不正确的逻辑,会导致丢失唤醒问题:这是一个反复出现的错误的名称,它困扰着错误编写的多线程程序。

条件变量是无状态的。如果在当前没有线程等待的情况下调用

pthread_cond_signal
pthread_cond_broadcast
,则该操作无效。它不被记住。 因此,您的信号线程可以非常快速地计数到
10
,并在另一个线程到达
pthread_cond_wait
调用之前向条件变量发出信号。

你需要绕一圈

pthread_cond_wait
。必须检查条件是否已为真,以便线程不会等待已经发生的唤醒。它应该是一个循环,因为唤醒可能是虚假的:仅仅因为线程通过
pthread_cond_wait
并不意味着条件实际上为真:

while (cont < 10)
  pthread_cond_wait(&cond, &myMutex);

此外,不需要仅仅为了使线程可连接而创建线程属性。这是当您对创建属性使用空指针时的默认情况。 POSIX 线程是可连接的,除非创建为分离的,或者使用

pthread_detach
转换为分离的。

另一件事:只要有可能,就避免在持有互斥锁时调用

pthread_cond_signal
。这并没有错,但可能很浪费,因为该操作实际上可能必须调用操作系统内核来唤醒线程,因此您在整个系统调用中都持有这个昂贵的互斥锁(当您真正需要它时)正在保护一些与应用程序中的共享数据一起使用的机器指令)。


2
投票

我不知道你的实际问题是什么(当它不起作用时会发生什么?)..

我发现一个主要问题,你没有处理虚假唤醒

您需要一些东西来表明条件确实为真,例如使用布尔变量:

初始化:

signaled = false;

信号:

signaled = true;
pthread_cond_signal(&cond);

接收:

while (!signaled)
   pthread_cond_wait(&cond, &myMutex);

1
投票

您想要的是信号量而不是条件变量。

信号量维护状态并对其进行计数 wait() 和 Signals()。
它通常使用条件变量来实现。

查看这里,了解一个简单的实现。


0
投票

这只是一个想法,但您也可以使用信号量来进行“触发”。我记得我不久前从事的一个项目,我们所做的是,当我们的一个线程等待被触发(使用 sem_wait)时,它只会等待无限的时间来尝试获取锁(因此被取消)调度程序的过程并节省宝贵的周期)。一旦主线程完成计算,它将释放信号量,允许第二个线程进行计算。

这只是一个不同的选择。

© www.soinside.com 2019 - 2024. All rights reserved.