具有互斥资源的多线程程序
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()
调用的假设是合理的。
总的来说,如果您想根据线程的某些特征排序 线程活动,那么您必须自己进行管理。您需要保持对轮到哪个线程的感觉,并提供一种机制足以让线程在轮到它时发出通知。在某些情况下,只要小心,您可以使用信号量而不是互斥量来做到这一点。然而,更通用的解决方案是将 条件变量 与互斥锁一起使用,以及一些共享变量来指示当前轮到谁。
我尝试构建一个程序,它应该创建线程并为每个线程分配一个 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()
调用的假设是合理的。
总的来说,如果您想根据线程的某些特征排序 线程活动,那么您必须自己进行管理。您需要保持对轮到哪个线程的感觉,并提供一种机制足以让线程在轮到它时发出通知。在某些情况下,只要小心,您可以使用信号量而不是互斥量来做到这一点。然而,更通用的解决方案是将 条件变量 与互斥锁一起使用,以及一些共享变量来指示当前轮到谁。