通过10个pthreads使用共享变量

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 (&params.mutex , NULL);

    int i;
    for(i = 0; i < 10; i++) {
            params.id = i;
            if(pthread_create(&threads[i], NULL, hello, &params));
    }

    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它可以是这些数字的任意组合,但每一个应该只出现一次.

Jay*_*Jay 7

问题出在下面的代码中:

for(i = 0; i < 10; i++) 
{             
  params.id = i;             
 if(pthread_create(&threads[i], NULL, hello, &params));     
} 
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更新之前打印它,有两种方式:

  • 确保线程0在主更新值之前完成执行和打印
  • 使用条件变量和信令确保主线程在更新值之前等待线程0完成打印(有关详细信息,请参阅下面的Arjun的答案)

老实说,你选择了错误的学习同步和共享内存的问题.你可以尝试一些像"生产者 - 消费者"这样的好问题,你真正需要同步工作.


Arj*_*kar 2

有两个问题:

答:您正在使用,lockmain不知道有这个锁。

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 (&params.mutex , NULL);
    pthread_cond_init (&params.done, NULL);

    /* Obtain a lock on the parameter.  */
    pthread_mutex_lock (&params.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, &params);

            /* Give up the lock, wait till thread is 'done',
            then reacquire the lock.  */
            pthread_cond_wait (&params.done, &params.mutex);
    }

    for(i = 0; i < 10; i++) {
            pthread_join(threads[i], NULL);
    }

    /* Destroy all synchronization primitives.  */    
    pthread_mutex_destroy (&params.mutex);
    pthread_cond_destroy (&params.done);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我看到您正在尝试的示例是一个玩具程序,可能用于了解 POSIX 线程库。在现实世界中,众所周知,这甚至可以在不使用线程的情况下更快地完成。但你已经知道这一点了。