pthread_cond_timedwait 代替sleep

news/2024/5/19 0:13:46 标签: thread, null, join, signal, struct, 多线程

linux多线程编程,你还在用sleep么?用pthread_cond_timedwait吧

摘要:多线程编程中,线程A循环计算,然后sleep一会接着计算(目的是减少CPU利用率);存在的问题是,如果要关闭程序,通常选择join线程A等待线程A退出,可是我们必须等到sleep函数返回,该线程A才能正常退出,这无疑减慢了程序退出的速度。当然,你可以terminate线程A,但这样做很不优雅,且会存在一些未知问题。采用pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t *mutex, const struct timespec * abstime)可以优雅的解决该问题,设置等待条件变量cond,如果超时,则返回;如果等待到条件变量cond,也返回。本文暂不将内部机理,仅演示一个demo。

首先,看这段代码,thr_fn为一个线程函数:

bool flag = true;
void * thr_fn(void * arg) {
  while (flag){
    printf(".\n");
    sleep(10);
  }
  printf("thread exit\n");
}
 
int main() {
  pthread_t thread;
  if (0 != pthread_create(&thread, NULL, thr_fn, NULL)) {
    printf("error when create pthread,%d\n", errno);
    return 1;
  }
 
  char c ;
  while ((c = getchar()) != 'q');
 
  printf("Now terminate the thread!\n");
  flag = false;
  printf("Wait for thread to exit\n");
  pthread_join(thread, NULL);
  printf("Bye\n");
  return 0;
}
输入q后,需要等线程从sleep中醒来(由挂起状态变为运行状态),即最坏情况要等10s,线程才会被join。采用sleep的缺点:不能及时唤醒线程。

采用pthread_cond_timedwait函数实现的如下:

#include <stdio.h>
#include <sys/time.h>;
#include <unistd.h>;
#include <pthread.h>;
#include <errno.h>;
 
pthread_t thread;
pthread_cond_t cond;
pthread_mutex_t mutex;
bool flag = true;
 
void * thr_fn(void * arg) {
  struct timeval now;
  struct timespec outtime;
  pthread_mutex_lock(&mutex);
  while (flag) {
    printf(".\n");
    gettimeofday(&now, NULL);
    outtime.tv_sec = now.tv_sec + 5;
    outtime.tv_nsec = now.tv_usec * 1000;
    pthread_cond_timedwait(&cond, &mutex, &outtime);
  }
  pthread_mutex_unlock(&mutex);
  printf("thread exit\n");
}
 
int main() {
  pthread_mutex_init(&mutex, NULL);
  pthread_cond_init(&cond, NULL);
  if (0 != pthread_create(&thread, NULL, thr_fn, NULL)) {
    printf("error when create pthread,%d\n", errno);
    return 1;
  }
  char c ;
  while ((c = getchar()) != 'q');
  printf("Now terminate the thread!\n");
  flag = false;
  pthread_mutex_lock(&mutex);
  pthread_cond_signal(&cond);
  pthread_mutex_unlock(&mutex);
  printf("Wait for thread to exit\n");
  pthread_join(thread, NULL);
  printf("Bye\n");
  return 0;
}
说明(翻译摘要中提供的连接,翻译的不好,凑合的看吧):

pthread_cond_timedwait()函数阻塞住调用该函数的线程,等待由cond指定的条件被触发(pthread_cond_broadcast() or pthread_cond_signal())。

当pthread_cond_timedwait()被调用时,调用线程必须已经锁住了mutex。函数pthread_cond_timedwait()会对mutex进行【解锁和执行对条件的等待】(原子操作)。这里的原子意味着:解锁和执行条件的等待是原则的,一体的。(In this case, atomically means with respect to the mutex and the condition variable and other access by threads to those objects through the pthread condition variable interfaces.)

如果等待条件满足或超时,或线程被取消,调用线程需要在线程继续执行前先自动锁住mutex,如果没有锁住mutex,产生EPERM错误。即,该函数返回时,mutex已经被调用线程锁住。

等待的时间通过abstime参数(绝对系统时间,过了该时刻就超时)指定,超时则返回ETIMEDOUT错误码。开始等待后,等待时间不受系统时钟改变的影响。

尽管时间通过秒和纳秒指定,系统时间是毫秒粒度的。需要根据调度和优先级原因,设置的时间长度应该比预想的时间要多或者少点。可以通过使用系统时钟接口gettimeofday()获得timeval结构体。

注: 为了可靠的使用条件变量和确保不忘记对条件变量的唤醒操作,应该采用一个bool变量和mutex变量同条件变量配合使用。如本文demo。



http://www.niftyadmin.cn/n/1116405.html

相关文章

2015阿里前端工程师在线笔试整理

昨天下午参加了阿里前端的笔试&#xff0c;题目是随机的&#xff0c;但好像越到后面题目越难。建议小伙伴们还是尽早参加。 总体来说&#xff0c;题目不算很难&#xff0c;有时间都是可以做出来的&#xff0c;总共11道题&#xff0c;6道单选&#xff0c;3道填空&#xff0c;两道…

微信冷知识|那些朋友圈文字被折叠的原因所在

嘿&#xff01;朋友们&#xff01;经常刷朋友圈的你有没有发现朋友圈里面有些内容会被折叠起来&#xff0c;而有些却不会呢&#xff1f; 你是否会考虑与文字内容的长短有关系&#xff1f; 其实&#xff0c;非也&#xff01; 是不是很疑惑&#xff1f;下面就让小编带你们深度了解…

pthread_cond_wait()用法分析

很久没看APUE&#xff0c;今天一位朋友问道关于一个mutex的问题&#xff0c;又翻到了以前讨论过的东西&#xff0c;为了不让自己忘记&#xff0c;把曾经的东西总结一下。 先大体看下网上很多地方都有的关于pthread_cond_wait()的说明&#xff1a; 条件变量 条件变量是…

输入1~8,每个数字不重复

昨天我的小伙伴可能太无聊了&#xff0c;然后给我一道题&#xff1a;输入1~8&#xff0c;每个数字不重复&#xff0c;问正确结果是什么&#xff1f; 这道题不难&#xff0c;把纵横计算式写出来&#xff08;一共6个&#xff09;&#xff0c;1~8全排列摆放在上面的8个空位上&…

当GetWindowText获取不到标题时可以用SendMessage

GetWindowText所有父窗口标题基本可以获取到&#xff0c; 但是当获取父窗口下的子窗口控件标题文本时有时候就没那么好用了&#xff0c; 这个时候可以通过SendMessage发送消息来获取&#xff0c;也很简单&#xff0c;C/C代码贴出来&#xff1a; 1 #include <iostream>2 #…

自定义依赖注入类,框架

模型 internal class Keyco<T> where T : class,new(){public T t;/// <summary>/// 构造函数/// </summary>public Keyco(){t new T();}/// <summary>获取传入的k/// </summary>/// <typeparam name"K">接口类型</typepara…

Android 硬件传感器

为什么80%的码农都做不了架构师&#xff1f;>>> 1. 传感器入门 自从苹果公司在2007年发布第一代iPhone以来&#xff0c;以前看似和手机挨不着边的传感器也逐渐成为手机硬件的重要组成部分。如果读者使用过iPhone、HTC Dream、HTC Magic、HTC Hero以及其他的Androi…

linux 线程 信号量

原来总是用互斥锁&#xff08;MUTEX&#xff09;和环境变量&#xff08;cond&#xff09;去控制线程的通信&#xff0c;用起来挺麻烦的&#xff0c;用信号量&#xff08;SEM&#xff09;来通信控制就方便多了&#xff01; 用到信号量就要包含semaphore.h头文件。 可以用sem_t类…