简体   繁体   English

Linux中C语言中的线程同步

[英]Thread Synchronization in Linux in C

I am having issue synchronizing the threads so each thread can run one job first, then another thread start the same job, and so on. 我在同步线程时遇到问题,因此每个线程可以先运行一个作业,然后另一个线程启动相同的作业,依此类推。 Below is my code: 下面是我的代码:

#include <unistd.h>
#include <sys/types.h> 
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <semaphore.h>

void handler ( void *ptr );
sem_t mutex;

int worker = 2; // number of workers
int job = 4; // number of jobs for each worker

int main()
{

    int i = 0;
    pthread_t thread_a;

    sem_init(&mutex, 0, 1);

    for (i; i < worker; i++)
    {  
       int *n_workers = malloc(sizeof(*n_workers));  
       *n_workers = i;                   
       pthread_create (&thread_a, NULL, (void *) &handler, n_workers);
    }

    pthread_join(thread_a, NULL);

    sem_destroy(&mutex);

    pthread_exit(0);
}

void handler ( void *ptr )
{
    int x = *((int *) ptr);
    int i = 0;

    for (i; i < job; i++)
    {
       sem_wait(&mutex);
       printf("Worker %d: Doing Job %d\n", x, i);  
       sem_post(&mutex);
    }
}

The output is : 输出为:

Worker 1: Doing Job 0
Worker 1: Doing Job 1
Worker 1: Doing Job 2
Worker 1: Doing Job 3
Worker 0: Doing Job 0
Worker 0: Doing Job 1
Worker 0: Doing Job 2
Worker 0: Doing Job 3

In the program, each worker has 4 jobs and there are 2 workers. 在该计划中,每个工人有4个工作,并且有2个工人。 The problem is that worker 1 does all 4 jobs at once and worker 0 does that all jobs after it. 问题在于,工作者1一次完成所有4个工作,而工作者0一次完成所有工作。 The ideal output would be this: 理想的输出是这样的:

Worker 0: Doing Job 0
Worker 1: Doing Job 0
Worker 0: Doing Job 1
Worker 1: Doing Job 1
Worker 0: Doing Job 2
Worker 1: Doing Job 2
Worker 0: Doing Job 3
Worker 1: Doing Job 3

I am not sure where the issue is here, any help is greatly appreciated. 我不确定问题出在哪里,任何帮助将不胜感激。 Thanks 谢谢

If you want to ensure that each thread does job[n] before job[n+1], you'll need to use barriers , either by implementing them using semaphores (for that you might want to consult The Little Book of Semaphores ), or using pthread_barrier_t . 如果要确保每个线程在job [n + 1]之前先完成job [n],则需要使用barrier ,方法是使用信号量实现它们(为此,您可能需要查阅《信号量小书》 ),或使用pthread_barrier_t

If you choose the latter, you should be able to achieve the effect with minimal modifications to your code: 如果选择后者,则只需对代码进行最少的修改就可以实现效果:

#include <unistd.h>
#include <sys/types.h> 
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <semaphore.h>

void handler ( void *ptr );
pthread_barrier_t barrier;

int worker = 2; // number of workers
int job = 4; // number of jobs for each worker

int main()
{

    int i = 0;
    pthread_t thread_a;

    pthread_barrier_init(&barrier, NULL, worker);

    for (i; i < worker; i++)
    {  
       int *n_workers = malloc(sizeof(*n_workers));  
       *n_workers = i;                   
       pthread_create (&thread_a, NULL, (void *) &handler, n_workers);
    }

    pthread_join(thread_a, NULL);

    pthread_barrier_destroy(&barrier);

    pthread_exit(0);
}

void handler ( void *ptr )
{
    int x = *((int *) ptr);
    int i = 0;

    for (i; i < job; i++)
    {
       printf("Worker %d: Doing Job %d\n", x, i);  
       pthread_barrier_wait(&barrier);
    }
}

This way, each job[n] gets executed int worker = 2 times before work on job[n+1] starts. 这样,每个作业[n]在作业[n + 1]上的工作开始之前将被执行int worker = 2次。 The order in which workers work on job[n] doesn't matter, so you might get different outputs, for example: 工人完成工作的顺序[n]无关紧要,因此您可能会获得不同的输出,例如:

Worker 0: Doing Job 0
Worker 1: Doing Job 0
Worker 1: Doing Job 1
Worker 0: Doing Job 1
Worker 0: Doing Job 2
Worker 1: Doing Job 2
Worker 0: Doing Job 3
Worker 1: Doing Job 3

What's important is the rightmost column. 重要的是最右边的列。

It seems what you want strict alternation, which is not what you have implemented in your example. 似乎您想要严格的轮换,而不是您在示例中实现的轮换。 What your code instead does is making sure that the your threads' "jobs" are executed by at most one thread at a time. 相反,您的代码所做的是确保线程的“作业”一次最多由一个线程执行。

Now every thread, when it gets scheduled gets a 'time-slice', a maximum amount of time that the thread may run. 现在,每个线程在进行调度时都会得到一个“时间片”,即该线程可以运行的最大时间。 If it is not be forced to sleep by, eg a blocking operation it will not give up the CPU until this time-slice is completely consumed. 如果没有通过阻塞操作(例如阻塞操作)来强制其进入睡眠状态,则在此时间段被完全消耗之前,它不会放弃CPU。 That is exactly is happening here, as the sem_wait will never block for the first thread entering your critical region. 这正是在这里发生的,因为sem_wait永远不会因为第一个线程进入您的关键区域而阻塞。 You would have to use further synchronization to implement the strict alternation, if that is what you really want. 如果这是您真正想要的,则必须使用进一步的同步来实施严格的交替。

If you do not strictly need strict alternation, but just want to see the effect of multi-threading, you can also let the threads give up CPU voluntarily by calling int pthread_yield(void); 如果您不是严格需要严格的轮换,而只是想了解多线程的效果,则还可以通过调用int pthread_yield(void);让线程自愿放弃CPU int pthread_yield(void); after releasing the semaphore, to give other threads the possibility to run. 释放信号量后,让其他线程可以运行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM