并发编程——pthread

  • pthread_t,线程对象
  • 创建线程
    // 成功返回0
    int pthread_create(pthread_t *restrict thread, 							// 需要创建的线程对象
    				   const pthread_attr_t *restrict attr, 				// 线程的相关属性,通常设置为null
    				   void *(*start_routine)(void *), 						// 线程执行的函数
    				   void *restrict arg);									// 线程执行函数的参数
    
  • 终止线程
    void pthread_exit(void *retval);										// 用于存储返回值,通常设置为null
    
  • 挂起线程
    // 成功返回0
    int pthread_join(pthread_t thread, 										// 需要挂起的线程
    				 void **retval);										// 用于保存退出时线程的状态,通常设置为null
    
  • pthread_mutex_t,互斥信号量
  • 初始化、销毁互斥信号量
    // 成功返回0
    int pthread_mutex_init(pthread_mutex_t *restrict mutex, 				// 互斥信号量
    					   const pthread_mutexattr_t *restrict attr);		// 互斥信号量的相关属性,通常设置为null
    int pthread_mutex_destroy(pthread_mutex_t *mutex);						// 销毁互斥信号量
    
  • 锁、解锁互斥信号量
    // 成功返回0
    int pthread_mutex_lock(pthread_mutex_t *mutex);							// 锁住互斥信号量,若信号量已经被锁住,则等待
    int pthread_mutex_trylock(pthread_mutex_t *mutex);						// 尝试锁住互斥信号量,若信号量已经被锁住,则直接返回
    int pthread_mutex_unlock(pthread_mutex_t *mutex);						// 解锁互斥信号量
    
  • pthread_cond_t,条件信号量
  • 初始化、销毁条件信号量
    // 成功返回0
    int pthread_cond_init(pthread_cond_t *restrict cond,					// 条件信号量
           				  const pthread_condattr_t *restrict attr);			// 条件信号量的相关属性,通常设置为null
    int pthread_cond_destroy(pthread_cond_t *cond);							// 销毁条件信号量
    
  • 等待条件信号量
    // 成功返回0
    // block条件信号量,直到收到条件信号量,再atomically释放互斥信号量
    int pthread_cond_wait(pthread_cond_t *restrict cond,					// 条件信号量
    					  pthread_mutex_t *restrict mutex);					// 互斥信号量
    // 功能同pthread_cond_wait(),但block被设定了时间,到时后,直接返回
    int pthread_cond_timedwait(pthread_cond_t *restrict cond,				// 条件信号量
    						   pthread_mutex_t *restrict mutex,				// 互斥信号量
    						   const struct timespec *restrict abstime);	// (绝对)等待时间
    
  • 通知条件信号量
    int pthread_cond_signal(pthread_cond_t *cond);							// unblock至少1个被指定条件信号量block的线程
    int pthread_cond_broadcast(pthread_cond_t *cond);						// unblock所有被指定条件信号量block的线程
    

例子,生产者-消费者问题

#include <iostream>
#include <pthread.h>
#include <queue>

#define TIME_OUT 1

struct ThreadParam {
  uint32_t thread_id;
  uint32_t num_cakes;
};

struct Buffer {
  inline void produce_cake(uint32_t id) {
    std::cout << id << "th producer produces " << cake_id << "th cake" 
              << std::endl;
    que.push(cake_id);
    cake_id ++;
  }

  inline uint32_t consume_cake(uint32_t id) {
    uint32_t cake = que.front();
    que.pop();
    std::cout << id << "th consumer consumes " << cake << "th cake" 
              << std::endl;
    return cake;
  }

  inline bool empty() { return que.empty(); }

  inline bool full() { return que.size() >= MAX_BUFFER_SIZE; }

  uint32_t cake_id = 0;
  std::queue<uint32_t> que;
  const uint32_t MAX_BUFFER_SIZE = 10;
};

Buffer buf;
uint32_t tot_num_cakes = 0;
uint32_t max_num_cakes = 0;

pthread_mutex_t buf_lock;
pthread_cond_t to_produce, to_consume;

void* produce(void* param) {
  ThreadParam* tp = (ThreadParam*)param;
  for (uint32_t i = 0; i < tp->num_cakes; ++ i) {
    pthread_mutex_lock(&buf_lock);
    // if buffer is full already, wait the singal to produce
    while (buf.full()) {
      pthread_cond_wait(&to_produce, &buf_lock);
    }
    buf.produce_cake(tp->thread_id);
    // Tell consumers to consume cakes
    pthread_mutex_unlock(&buf_lock);
    pthread_cond_broadcast(&to_consume);
  }
  std::cout << tp->thread_id << "th producer finishes" << std::endl;
  pthread_exit(nullptr);
  return nullptr;
}

void* consume(void* param) {
  ThreadParam* tp = (ThreadParam*)param;
  while (true) {
    if (tot_num_cakes >= max_num_cakes) {
      break;
    }
    pthread_mutex_lock(&buf_lock);
    struct timespec end_time;
    end_time.tv_sec = time(nullptr) + TIME_OUT;
    end_time.tv_nsec = 0;
    // if buffer is empty, wait the signal to consume in the given timelimits
    if (buf.empty()) {
      pthread_cond_timedwait(&to_consume, &buf_lock, &end_time);
    } else {
      uint32_t cake = buf.consume_cake(tp->thread_id);
      tp->num_cakes ++;
      tot_num_cakes ++;
    }
    pthread_mutex_unlock(&buf_lock);
    // Tell producers to produce cakes
    pthread_cond_broadcast(&to_produce);
  }
  std::cout << tp->thread_id << "th consumer finishes" << std::endl;
  pthread_exit(nullptr);
  return nullptr;
}

int main() {
  uint32_t num_cakes = 10;
  uint32_t num_threads = 4;
  pthread_t threads[num_threads];
  ThreadParam tp[num_threads];
  max_num_cakes = num_cakes * (num_threads / 2);

  pthread_mutex_init(&buf_lock, nullptr);
  pthread_cond_init(&to_produce, nullptr);
  pthread_cond_init(&to_consume, nullptr);

  // Create producers
  for (uint32_t i = 0; i < num_threads / 2; ++ i) {
    tp[i].thread_id = i;
    tp[i].num_cakes = num_cakes;
    int rc = pthread_create(&threads[i], nullptr, produce, (void*)&tp[i]);
    if (rc) {
      std::cerr << "Cannot create new producers, return code [" << rc << "]" 
                << std::endl;
      exit(-1);
    }
  }
  
  // Create consumers
  for (uint32_t i = num_threads / 2; i < num_threads; ++ i) {
    tp[i].thread_id = i;
    tp[i].num_cakes = 0;
    int rc = pthread_create(&threads[i], nullptr, consume, (void*)&tp[i]);
    if (rc) {
      std::cerr << "Cannot create new consumers, return code [" << rc << "]" 
                << std::endl;
      exit(-1);
    }
  }
  
  for (uint32_t i = 0; i < num_threads; ++ i) {
    pthread_join(threads[i], nullptr);
  }
  for (uint32_t i = num_threads / 2; i < num_threads; ++ i) {
    std::cout << i << "th consumer consumes " << tp[i].num_cakes << std::endl;
  }

  pthread_mutex_destroy(&buf_lock);
  pthread_cond_destroy(&to_produce);
  pthread_cond_destroy(&to_consume);
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值