具有互斥资源的多线程程序

Multithreaded program with mutex on mutual resource

我尝试构建一个程序,它应该创建线程并为每个线程分配一个 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;
}

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

而是通过转换为 void* 的值传递它。

修复:

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

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

在for循环中创建的所有线程都有不同的值indx。由于操作系统调度程序,您永远无法确定哪个线程将 运行。因此,打印的值是随机顺序的,具体取决于调度程序的随机性。父线程中的第二个 for 循环 运行ning 将在创建子线程后立即 运行。同样,调度程序决定下一个线程应该 运行 的顺序。

每个 OS 都应该有一个中断(至少主要操作系统有)。当 运行 在父线程中执行 for 循环时,可能会发生中断并让调度程序决定将哪个线程分配给 运行。因此,父循环中打印的数字是随机打印的,因为所有线程 运行 "concurrently".

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

尽管存在程序错误的所有问题,pthreads 互斥体提供 mutual exclusion ,不保证调度顺序。这是典型的互斥实现。同样,pthread_create() 只创建和启动线程;它不对调度顺序做出任何保证,例如可以证明线程以与创建它们相同的顺序到达 pthread_mutex_lock() 调用的假设是合理的。

总的来说,如果您想根据线程的某些特征排序 线程活动,那么您必须自己进行管理。您需要保持对轮到哪个线程的感觉,并提供一种机制足以让线程在轮到它时发出通知。在某些情况下,只要小心,您可以使用信号量而不是互斥量来做到这一点。然而,更通用的解决方案是将 条件变量 与互斥锁一起使用,以及一些共享变量来指示当前轮到谁。