【问题标题】:thread synchronization for two threads using one semaphore使用一个信号量实现两个线程的线程同步
【发布时间】:2016-05-28 12:43:35
【问题描述】:

我想同步线程以打印 1 到 20,其中线程 1 打印奇数,线程 2 打印偶数

我用两个信号量实现了这一点。

问题:

1) 是否可以仅使用一个信号量来实现?

2) 有没有有效的方法来实现这一点?

如果可能,也请提供示例。

sem_t bin_sem1, bin_sem2;
int count = 1;

int main()
{
    int ret;
    pthread_t a_thread, b_thread;

    ret = sem_init(&bin_sem1, 0, 1);
    if (ret != 0)
    {
        perror("semaphore1 initialization failed\n");
        exit(EXIT_FAILURE);
    }
    ret = sem_init(&bin_sem2, 0, 0);
    if (ret != 0)
    {
        perror("semaphore2 initialization failed\n");
        exit(EXIT_FAILURE);
    }

    ret = pthread_create(&a_thread, NULL, thread_fun1, NULL);
    if (ret != 0)
    {
        perror("Thread1 creation failed");
        exit(EXIT_FAILURE);
    }

    ret = pthread_create(&b_thread, NULL, thread_fun2, NULL);
    if (ret != 0)
    {
        perror("Thread2 creation failed");
        exit(EXIT_FAILURE);
    }

    printf("Waiting for threads to finish\n");
    ret = pthread_join(a_thread, NULL);
    if (ret != 0)
    {
        perror("Thread1 join failed");
        exit(EXIT_FAILURE);
    }
    printf("Thread1 joined");

    ret = pthread_join(b_thread, NULL);
    if (ret != 0)
    {
        perror("Thread2 join failed");
        exit(EXIT_FAILURE);
    }
    printf("Thread2 joined");

    exit(EXIT_SUCCESS);
}

void *thread_fun1(void *arg)
{
    int val=0, val2=0;
    while (count < 20)
    {
        sem_wait(&bin_sem1);
        sem_getvalue(&bin_sem1, &val);sem_getvalue(&bin_sem2, &val2);
        printf("T 1 : after wait  : sem 1 = %d, sem 2 = %d\n", val, val2);

        printf("T 1 : count = %d\n", count++);

        sem_post(&bin_sem2);
        sem_getvalue(&bin_sem1, &val);sem_getvalue(&bin_sem2, &val2);
        printf("T 1 : after post  : sem 1 = %d, sem 2 = %d\n", val, val2);
    }
    pthread_exit(NULL);
}
void *thread_fun2(void *arg)
{
    int val=0, val2=0;
    while (count < 20)
    {
        sem_wait(&bin_sem2);
        sem_getvalue(&bin_sem1, &val);sem_getvalue(&bin_sem2, &val2);
        printf("\t\t\t\t\t\tT 2 : after wait  : sem 1 = %d, sem 2 = %d\n", val, val2);

        printf("\t\t\t\t\t\tT 2 : count = %d\n", count++);

        sem_post(&bin_sem1);
        sem_getvalue(&bin_sem1, &val);sem_getvalue(&bin_sem2, &val2);
        printf("\t\t\t\t\t\tT 2 : after post  : sem 1 = %d, sem 2 = %d\n", val, val2);
    }
    pthread_exit(NULL);
}

【问题讨论】:

  • 不使用信号量,为什么不使用原子类型?
  • @Linus 一般,因为你不能等待他们。

标签: c multithreading synchronization mutex semaphore


【解决方案1】:

嗯,可以只使用一个信号量,但以一种 hacky 的方式。您可以使用它存储实际值,然后在线程 2 中打印偶数,在线程 1 中打印奇数,而不是使用像互斥锁这样的信号量。这是一个示例,但不是从 1 打印到 20,而是从 20 打印到1,但如果需要,可以轻松修改。

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>

void *a_func(void *arg) {
  sem_t *mySem = (sem_t *) arg;
  int value = 20;

  while (value > 0) {
    if (value % 2 == 1) {
      printf("thread 1 : %d\n", value);
      sem_wait(mySem);
    }
    sem_getvalue(mySem, &value);
  }
}

void *b_func(void *arg) {
  sem_t *mySem = (sem_t *) arg;
  int value = 20;

  while (value > 0) {
    if (value % 2 == 0) {
      printf("thread 2 : %d\n", value);
      sem_wait(mySem);
    }
    sem_getvalue(mySem, &value);
  }
}

int main() {
  sem_t mySem;
  pthread_t a_thread, b_thread;

  if (sem_init(&mySem, 0, 20)) {
    // handle error
  }

  if (pthread_create(&a_thread, NULL, a_func, &mySem)) {
    // handle error
  }

  if (pthread_create(&b_thread, NULL, b_func, &mySem)) {
    // handle error
  }

  // wait for threads to finish
  pthread_join(a_thread, NULL);
  pthread_join(b_thread, NULL);
}

但是,信号量很少以这种方式使用,因此我建议使用更现代且非常适合您的用例的原子类型。这是一个简单的例子:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <stdatomic.h>

void *a_func(void *arg) {
  atomic_int *myInt = (atomic_int *) arg;
  int value = 20;

  while (value > 0) {
    if (value % 2 == 1) {
      //printf("thread 1 : %d\n", value);
      value = atomic_fetch_sub(myInt, 1) + 1;
      continue;
    }
    value = atomic_load(myInt);
  }
}

void *b_func(void *arg) {
  atomic_int *myInt = (atomic_int *) arg;
  int value = 20;

  while (value > 0) {
    if (value % 2 == 0) {
      //printf("thread 2 : %d\n", value);
      value = atomic_fetch_sub(myInt, 1) + 1;
      continue;
    }
    value = atomic_load(myInt);
  }
}

int main() {
  atomic_int myInt = ATOMIC_VAR_INIT(20); // set myInt to 20
  pthread_t a_thread, b_thread;

  if (pthread_create(&a_thread, NULL, a_func, &myInt)) {
    // handle error
  }

  if (pthread_create(&b_thread, NULL, b_func, &myInt)) {
    // handle error
  }

  // wait for threads to finish
  pthread_join(a_thread, NULL);
  pthread_join(b_thread, NULL);
}

就性能而言,单个信号量程序和基于原子类型的程序的运行速度都比您提供的代码快得多。但是,在这个仅使用 1-20 范围内的数字的规模上,性能差异可以忽略不计。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-06
    相关资源
    最近更新 更多