Ale*_*lex 6 c linux mutex pthreads
问题在于:
我想写一个创建10个线程的短程序,每个程序打印一个通过指针传递给线程函数的"id".
该计划的完整代码如下:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
struct params {
pthread_mutex_t mutex;
int id;
};
typedef struct params params_t;
void* hello(void* arg){
int id;
pthread_mutex_lock(&(*(params_t*)(arg)).mutex);
id = (*(params_t*)(arg)).id;
pthread_mutex_unlock(&(*(params_t*)(arg)).mutex);
printf("Hello from %d\n", id);
}
int main() {
pthread_t threads[10];
params_t params;
pthread_mutex_init (¶ms.mutex , NULL);
int i;
for(i = 0; i < 10; i++) {
params.id = i;
if(pthread_create(&threads[i], NULL, hello, ¶ms));
}
for(i = 0; i < 10; i++) {
pthread_join(threads[i], NULL);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
假定的输出(按此顺序不必要):
Hello from 0
....
Hello from 9
Run Code Online (Sandbox Code Playgroud)
实际结果是:
Hello from 2
Hello from 3
Hello from 3
Hello from 4
Hello from 5
Hello from 6
Hello from 8
Hello from 9
Hello from 9
Hello from 9
Run Code Online (Sandbox Code Playgroud)
我尝试将互斥锁置于hello()功能的不同位置,但它没有帮助.
我该如何实现线程同步?
编辑:假设结果不是必要的0 ... 9它可以是这些数字的任意组合,但每一个应该只出现一次.
问题出在下面的代码中:
for(i = 0; i < 10; i++)
{
params.id = i;
if(pthread_create(&threads[i], NULL, hello, ¶ms));
}
Run Code Online (Sandbox Code Playgroud)
你的params.id值在主线程中不断更新,而你将相同的指针传递给所有线程.
请通过动态分配params为params创建单独的内存并将其传递给不同的线程来解决问题.
编辑1: 您使用互斥锁进行保护也是一个错误的想法.虽然你的互斥锁如果在主设备中使用时也可以设置id,可能会使更新互斥,但你可能无法获得所需的输出.不是在不同的线程中从0 ... 9获取值,而是可以获得所有9个或仍然多个线程可以打印相同的值.
因此,对于您期望的输出,使用线程同步并不是一个好主意.如果你仍然需要在所有线程之间使用一个param变量并从每个线程获得0到9的输出,那么最好将pthread_join移动到第一个循环中.这将确保每个线程都被创建,打印该值,然后在main生成下一个线程之前返回.在这种情况下,您也不需要互斥锁.
编辑2: 至于更新的问题,在被要求不必按顺序打印数字0..9的情况下,打印可以是随机的,但只有一次,问题仍然或多或少地保持不变.
现在,让我们说,params.id的值是0,线程0已经创建,现在,线程0必须在主线程中更新之前打印它,否则,当线程0访问它时,params.id的值会变成1,你永远不会得到你独特的价值观.那么,如何确保线程0在main更新之前打印它,有两种方式:
老实说,你选择了错误的学习同步和共享内存的问题.你可以尝试一些像"生产者 - 消费者"这样的好问题,你真正需要同步工作.
有两个问题:
答:您正在使用,lock但main不知道有这个锁。
B.lock在这种情况下 A 还不够。您希望线程通过相互发信号来进行协作(因为您希望在线程表示已完成打印之前main不要增加变量)。您可以使用 apthread_cond_t来实现此目的(请参阅此处以了解有关此内容的更多信息)。这可以归结为以下代码(基本上,我在您的代码中添加了适当的用法pthread_cond_t,以及一堆解释发生了什么的注释):
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
struct params {
pthread_mutex_t mutex;
pthread_cond_t done;
int id;
};
typedef struct params params_t;
void* hello(void* arg){
int id;
/* Lock. */
pthread_mutex_lock(&(*(params_t*)(arg)).mutex);
/* Work. */
id = (*(params_t*)(arg)).id;
printf("Hello from %d\n", id);
/* Unlock and signal completion. */
pthread_mutex_unlock(&(*(params_t*)(arg)).mutex);
pthread_cond_signal (&(*(params_t*)(arg)).done);
/* After signalling `main`, the thread could actually
go on to do more work in parallel. */
}
int main() {
pthread_t threads[10];
params_t params;
pthread_mutex_init (¶ms.mutex , NULL);
pthread_cond_init (¶ms.done, NULL);
/* Obtain a lock on the parameter. */
pthread_mutex_lock (¶ms.mutex);
int i;
for(i = 0; i < 10; i++) {
/* Change the parameter (I own it). */
params.id = i;
/* Spawn a thread. */
pthread_create(&threads[i], NULL, hello, ¶ms);
/* Give up the lock, wait till thread is 'done',
then reacquire the lock. */
pthread_cond_wait (¶ms.done, ¶ms.mutex);
}
for(i = 0; i < 10; i++) {
pthread_join(threads[i], NULL);
}
/* Destroy all synchronization primitives. */
pthread_mutex_destroy (¶ms.mutex);
pthread_cond_destroy (¶ms.done);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我看到您正在尝试的示例是一个玩具程序,可能用于了解 POSIX 线程库。在现实世界中,众所周知,这甚至可以在不使用线程的情况下更快地完成。但你已经知道这一点了。