互斥互斥的多线程程序

时间:2019-03-22 13:36:17

标签: c multithreading pthreads mutex

我试图构建一个程序,该程序应创建线程并为每个线程分配一个Print函数,而主进程应直接使用printf函数。

首先,我在没有任何同步手段的情况下实现了这一目标,并期望获得随机输出。 后来我尝试将互斥锁添加到分配给线程的Print函数中,并希望获得按时间顺序排列的输出,但是互斥锁似乎对输出没有影响。

在主流程中,我也应该在printf函数上使用互斥吗?

预先感谢

我的代码:

#include <stdio.h>
#include <pthread.h>
#include <errno.h>

pthread_t threadID[20];
pthread_mutex_t lock;

void* Print(void* _num);

int main(void)
{
    int num = 20, indx = 0, k = 0;

    if (pthread_mutex_init(&lock, NULL))
    {
        perror("err pthread_mutex_init\n");
        return errno;
    }

    for (; indx < num; ++indx)
    {
        if (pthread_create(&threadID[indx], NULL, Print, &indx))
        {
            perror("err pthread_create\n");
            return errno;   
        }
    }

    for (; k < num; ++k)
    {
        printf("%d from main\n", k);
    }

    indx = 0; 

    for (; indx < num; ++indx)
    {
        if (pthread_join(threadID[indx], NULL))
        {
            perror("err pthread_join\n");
            return errno;   
        }
    }

    pthread_mutex_destroy(&lock);

    return 0;
}


void* Print(void* _indx)
{
    pthread_mutex_lock(&lock);

    printf("%d from thread\n", *(int*)_indx);

    pthread_mutex_unlock(&lock);

    return NULL;
}

3 个答案:

答案 0 :(得分:1)

该代码将同一局部变量的地址传递给所有线程。同时,此变量由主线程更新。

而是将其按值强制传递给void*

修复:

pthread_create(&threadID[indx], NULL, Print, (void*)indx)
// ...
printf("%d from thread\n", (int)_indx);

现在,由于线程之间没有共享数据,因此可以删除该互斥锁。

答案 1 :(得分:1)

尽管存在程序错误的所有问题,pthread互斥锁仅提供 mut ual ex ,但不能保证调度顺序。这是互斥体实现的典型代表。类似地,pthread_create()仅创建和启动线程。它并不能保证调度顺序,例如,可以假设线程以创建时的相同顺序到达pthread_mutex_lock()调用。

总体而言,如果您想根据线程的某些特征订购线程活动,则必须自己进行管理。您需要保持对线程转向的感觉,并提供一种足以在线程到达时通知线程的机制。在某些情况下,请谨慎使用信号量而不是互斥量。但是,更通用的解决方案是将条件变量与您的互斥锁一起使用,并使用一些共享变量来指示当前轮到谁了。

答案 2 :(得分:0)

在for循环中创建的所有线程具有不同的 indx 值。由于存在操作系统调度程序,因此您无法确定将运行哪个线程。因此,根据调度程序的随机性,打印的值是随机的。父线程中运行的第二个for循环将在创建子线程后立即运行。再次,调度程序决定下一步应运行什么线程的顺序。

每个操作系统都应有一个中断(至少主要操作系统有一个)。在父线程中运行for循环时,可能会发生中断并使调度程序决定要运行哪个线程。因此,在父for循环中打印的数字是随机打印的,因为所有线程都是“并行运行”的。

加入线程意味着等待线程。如果要确保按时间顺序在父for循环中打印所有数字,而又不让子线程中断它,则将for-loop部分重新定位在加入线程之后。