21xrx.com
2024-09-17 04:24:33 Tuesday
登录
文章检索 我的文章 写文章
C++多线程共享数据的实现方法和注意事项
2023-07-05 10:44:14 深夜i     --     --
C++多线程共享数据 实现方法 注意事项 线程安全 操作同步

在C++多线程编程中,共享数据是一件非常常见的事情。在多个线程同时访问同一份数据时,如果没有恰当的处理,就会导致数据不一致以及其他一些问题。因此,如何实现多线程共享数据是一个非常重要的问题。在这篇文章中,我们将介绍C++多线程共享数据的实现方法和注意事项。

一、实现方法

1. 互斥量

互斥量是一种用于保护共享资源的最基本的同步机制。它可以在多线程环境中确保只有一个线程可以访问共享资源。当一个线程占用了互斥量,其他线程就必须等待该线程释放互斥量后才能访问共享资源。互斥量的实现方式包括Windows API的CriticalSection和Mutex、Linux上的pthread_mutex_t、C++11标准库中的std::mutex等等。

例子:


#include <iostream>

#include <cstdlib>

#include <pthread.h>

using namespace std;

#define NUM_THREADS   5

int sum = 0;

pthread_mutex_t mutexsum;

void *PrintHello(void *threadid)

{

  long tid = (long)threadid;

  int randNum;

  randNum = rand() % 10 + 1;

  pthread_mutex_lock(&mutexsum);

  printf("Thread %ld: sum = %d, will increase sum by %d\n", tid, sum, randNum);

  sum += randNum;

  pthread_mutex_unlock(&mutexsum);

  printf("Thread %ld: now sum = %d\n", tid, sum);

  pthread_exit(NULL);

}

int main ()

{

  pthread_t threads[NUM_THREADS];

  int rc;

  long t;

  srand(time(NULL));

  pthread_mutex_init(&mutexsum, NULL);

  for(t=0; t<NUM_THREADS; t++){

   printf("Creating thread %ld\n", t);

   rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);

   if (rc){

     printf("ERROR; return code from pthread_create() is %d\n", rc);

     exit(-1);

   }

  }

  for(t=0; t<NUM_THREADS; t++){

   pthread_join(threads[t], NULL);

  }

  printf("Final sum = %d\n", sum);

  pthread_mutex_destroy(&mutexsum);

  pthread_exit(NULL);

}

2. 信号量

信号量也是一种同步机制,它用于在多线程环境中对多个线程之间的关系进行协调。一个信号量通过一个计数器来控制所允许的线程数。当一个线程请求一个信号量时,该计数器会减1;当一个线程释放一个信号量时,计数器会加1。当计数器为0时,其他线程就必须等待一个信号量被释放才能继续运行。信号量的实现方式包括Windows API的Semaphore和Mutex、Linux上的pthread_cond_t、C++11标准库中的std::condition_variable等等。

例子:


#include <iostream>

#include <cstdlib>

#include <pthread.h>

#include <semaphore.h>

using namespace std;

#define NUM_THREADS   5

#define MAX_SEM_COUNT  3

sem_t sem;

int sum = 0;

void *PrintHello(void *threadid)

{

  long tid = (long)threadid;

  int randNum;

  randNum = rand() % 10 + 1;

  sem_wait(&sem);

  printf("Thread %ld: sum = %d, will increase sum by %d\n", tid, sum, randNum);

  sum += randNum;

  printf("Thread %ld: now sum = %d\n", tid, sum);

  sem_post(&sem);

  pthread_exit(NULL);

}

int main ()

{

  pthread_t threads[NUM_THREADS];

  int rc;

  long t;

  srand(time(NULL));

  sem_init(&sem, 0, MAX_SEM_COUNT);

  for(t=0; t<NUM_THREADS; t++){

   printf("Creating thread %ld\n", t);

   rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);

   if (rc){

     printf("ERROR; return code from pthread_create() is %d\n", rc);

     exit(-1);

   }

  }

  for(t=0; t<NUM_THREADS; t++){

   pthread_join(threads[t], NULL);

  }

  printf("Final sum = %d\n", sum);

  sem_destroy(&sem);

  pthread_exit(NULL);

}

二、注意事项

1. 避免死锁

死锁是一种多线程编程中非常严重的问题。它发生时,多个线程都在等待彼此释放资源,导致程序无法继续运行。为了避免死锁,需要在编写程序时仔细考虑多个线程之间的协作关系,并注意锁的获取和释放顺序。

2. 避免竞争条件

竞争条件也是多线程编程中的另一个常见问题。它发生时,在多个线程对同一份数据进行读写时,某些线程对数据的修改可能会被其他线程的修改所覆盖。为了避免竞争条件,需要使用锁来保证数据的同步。

3. 避免饥饿

如果某个线程无法获取到锁,就会一直等待,这种现象被称为饥饿。为了避免饥饿,应该避免使用非公平锁,使用公平锁来控制线程的优先级。

4. 避免线程泄漏

线程泄漏是指程序创建了很多线程却没有销毁,导致程序消耗大量的系统资源。为了避免线程泄漏,应该在创建线程之前仔细考虑线程的数量,以及线程的生命周期,并且在不需要某个线程时及时销毁它。

在多线程编程中,共享数据的实现方法和注意事项都是非常重要的,只有充分理解和遵守这些要点,才能够写出正确、高效、健壮的多线程程序。

  
  

评论区

{{item['qq_nickname']}}
()
回复
回复