6

我写了一个程序,但它并没有像我期望的那样工作。我有两个线程:threadtriggersfuncanotherThreadtriggers anotherFunc。我想做的是当cont达到 , 的值时10使用and触发。奇怪的是,如果我取消注释该行,一切正常。我是线程的新手,我在这里遵循教程,如果我在他们的示例中评论该行,它也会中断。funcanotherThreadpthread_cond_waitpthread_cond_signalsleep(1)sleep

我的问题是如何在没有任何sleep()电话的情况下完成这项工作?如果在我的代码中都func达到pthread_mutex_lockafter会发生什么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;
}

抱歉,这篇文章很长,但我是线程新手,我愿意学习。你还知道一些关于 Linux 上线程和网络的很好的参考资料或课程/教程吗?我想学习创建一个聊天客户端,我听说我必须知道线程和网络。问题是我不知道我所学的东西是否很好,因为我不知道我必须知道什么。

非常感谢 :)

4

4 回答 4

9

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

条件变量是无状态的。如果在当前没有线程等待的条件下调用pthread_cond_signalor 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在持有互斥锁时调用。这不是不正确的,但它可能是浪费的,因为该操作实际上可能必须调用操作系统内核来唤醒一个线程,所以你在整个系统调用中持有这个昂贵的互斥锁(当你真正需要它的时候正在保护一些在您的应用程序中处理共享数据的机器指令)。

于 2012-04-16T18:36:11.050 回答
2

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

我看到了一个主要问题,您无法处理虚假唤醒

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

在里面:

signaled = false;

信号:

signaled = true;
pthread_cond_signal(&cond);

收到:

while (!signaled)
   pthread_cond_wait(&cond, &myMutex);
于 2012-04-16T18:38:49.393 回答
1

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

信号量维护状态并针对它计算 wait() 和 signals()。
它通常使用条件变量来实现。

在这里寻找一个简单的实现。

于 2012-04-16T18:55:52.163 回答
0

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

这只是一个不同的选择。

于 2012-04-16T18:52:09.257 回答