linux多线程编程,替代sleep的几种方式

本文探讨了在多线程环境中精确控制线程休眠的方法,包括usleep、select及pthread_cond_timedwait函数的使用,重点介绍了如何利用pthread_cond_timedwait实现线程的优雅休眠,避免了传统sleep函数的局限。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我只想要进程的某个线程休眠一段时间的,可是用sleep()是将整个进程都休眠的,这个可能就达不到,我们想要的效果了。 目前我知道有三种方式:

1 usleep

   这个是轻量级的, 听说能可一实现线程休眠, 我个人目前使用的这种。

2 select

   这个可以,我也用过这种方式, 它是在轮询。

3  pthread_cond_timedwait

        采用pthread_cond_timedwait(pthread_cond_t* cond, pthread_mutex_t *mutex, const struct timespec *abstime)可以优雅的解决该问题,设置等待条件变量cond,如果超时,则返回;如果等待到条件变量cond,也返回。本文暂不将内部机理,仅演示一个demo。

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

#include <stdio.h>
#include <stdlib.h>
 
int flag = 1;
void * thr_fn(void * arg) {
  while (flag){
    printf("******\n");
    sleep(10);
  }
  printf("sleep test 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 = 0;
  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>
 
static pthread_t thread;
static pthread_cond_t cond;
static pthread_mutex_t mutex;
static int flag = 1;
 
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("cond thread exit\n");
}
 
int main(void) 
{
  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");
 
  pthread_mutex_lock(&mutex);
  flag = 0;
  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 andthe condition variable and other access by threads to those objectsthrough the pthread condition variable interfaces.)

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

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

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

<think>在PyQt5中,如果你需要在工作线程中进行毫秒级的休眠,有几种方法可以实现。需要注意的是,由于`QThread.sleep()`系列方法在Qt5.8之后已被标记为废弃(deprecated),因此推荐使用以下替代方案: ### 方法1:使用Python标准库`time.sleep()` 虽然`time.sleep()`的参数是秒(浮点数),但你可以通过除以1000来实现毫秒级休眠: ```python import time time.sleep(0.05) # 休眠50毫秒 ``` ### 方法2:使用`QThread.msleep()`(已弃用,不推荐长期使用) ```python from PyQt5.QtCore import QThread class WorkerThread(QThread): def run(self): # 休眠50毫秒 QThread.msleep(50) # 注意:此方法已弃用 ``` ### 方法3:使用`QEventLoop`(推荐替代方案) 如果你需要非阻塞的等待(例如在等待期间保持事件循环运行),可以使用`QEventLoop`配合`QTimer`: ```python from PyQt5.QtCore import QTimer, QEventLoop def delay(milliseconds): loop = QEventLoop() QTimer.singleShot(milliseconds, loop.quit) loop.exec_() # 在工作线程中使用 delay(50) # 延迟50毫秒 ``` ### 方法4:使用`QTimer`单次触发(无需创建线程) 如果你的目的是定时执行某个操作,而不是在某个操作中插入等待,那么使用`QTimer`更合适: ```python from PyQt5.QtCore import QTimer QTimer.singleShot(50, lambda: print("50毫秒后执行")) ``` ### 完整示例(使用标准库实现毫秒级休眠) ```python import sys import time from PyQt5.QtWidgets import QApplication, QLabel, QPushButton, QVBoxLayout, QWidget from PyQt5.QtCore import QThread, pyqtSignal class WorkerThread(QThread): update_signal = pyqtSignal(str) def run(self): for i in range(1, 11): # 毫秒级休眠:500毫秒 time.sleep(0.5) # 500毫秒 = 0.5秒 self.update_signal.emit(f"步骤 {i}/10 完成") class MainWindow(QWidget): def __init__(self): super().__init__() self.label = QLabel("点击开始执行任务") self.btn = QPushButton("开始任务") layout = QVBoxLayout() layout.addWidget(self.label) layout.addWidget(self.btn) self.setLayout(layout) self.btn.clicked.connect(self.start_task) self.worker = WorkerThread() self.worker.update_signal.connect(self.update_label) def start_task(self): self.btn.setEnabled(False) self.worker.start() def update_label(self, text): self.label.setText(text) if text == "步骤 10/10 完成": self.btn.setEnabled(True) if __name__ == "__main__": app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec_()) ``` ### 注意事项 1. **精度问题**: - `time.sleep()`的实际精度取决于操作系统,通常能保证毫秒级精度,但在Windows系统下可能最低为15-20毫秒[^1]。 - 如果需要更高精度的定时,考虑使用`QTimer`或专用定时器库。 2. **线程安全**: - 在工作线程中休眠不会阻塞主线程,但要注意线程间的通信必须通过信号/槽机制。 3. **替代方案**: - 对于需要精确计时的场景(如实时系统),建议使用高性能定时器或专用硬件。 ### 相关问题 1. PyQt5中如何实现高精度定时器(微秒级)? 2. 为什么`QThread.sleep()`方法被标记为废弃?有什么替代方案? 3. 在PyQt5多线程编程中如何处理线程间同步问题?</think># PyQt5 线程毫秒级休眠实现指南 在 PyQt5 中实现线程的毫秒级休眠,需要避免阻塞主线程同时确保精确计时。以下是几种推荐方法: ## 推荐方法:使用 `time.sleep()` 实现毫秒级休眠 ```python import time from PyQt5.QtCore import QThread, pyqtSignal class MillisecondWorker(QThread): update_signal = pyqtSignal(str) def run(self): for i in range(1, 11): # 毫秒级休眠:500毫秒 = 0.5秒 time.sleep(0.5) # 使用浮点数指定毫秒 # 发送更新信号到主线程 self.update_signal.emit(f"步骤 {i}/10 完成 (500ms延迟)") ``` ## 替代方案:使用 `QThread.msleep()`(已弃用) ```python from PyQt5.QtCore import QThread class DeprecatedWorker(QThread): def run(self): # 毫秒级休眠 - 注意:此方法在Qt 5.8+已弃用 QThread.msleep(50) # 休眠50毫秒 ``` ## 完整示例:毫秒级休眠应用 ```python import sys import time from PyQt5.QtWidgets import (QApplication, QMainWindow, QLabel, QPushButton, QVBoxLayout, QWidget) from PyQt5.QtCore import QThread, pyqtSignal class WorkerThread(QThread): update_signal = pyqtSignal(str) finished = pyqtSignal() def __init__(self, delay_ms): super().__init__() self.delay_ms = delay_ms / 1000.0 # 毫秒转秒 def run(self): for i in range(1, 6): time.sleep(self.delay_ms) self.update_signal.emit(f"任务 {i}/5 完成 ({self.delay_ms*1000:.0f}ms延迟)") self.finished.emit() class MainWindow(QMainWindow): def __init__(self): super().__init__() # 创建UI self.setWindowTitle("毫秒级线程休眠示例") self.central_widget = QWidget() self.setCentralWidget(self.central_widget) self.label = QLabel("点击按钮启动线程任务") self.btn_100ms = QPushButton("启动100ms任务") self.btn_500ms = QPushButton("启动500ms任务") layout = QVBoxLayout() layout.addWidget(self.label) layout.addWidget(self.btn_100ms) layout.addWidget(self.btn_500ms) self.central_widget.setLayout(layout) # 连接信号 self.btn_100ms.clicked.connect(lambda: self.start_task(100)) self.btn_500ms.clicked.connect(lambda: self.start_task(500)) # 禁用按钮直到任务完成 self.worker = None def start_task(self, delay_ms): # 禁用所有按钮 self.btn_100ms.setEnabled(False) self.btn_500ms.setEnabled(False) # 创建并启动工作线程 self.worker = WorkerThread(delay_ms) self.worker.update_signal.connect(self.update_status) self.worker.finished.connect(self.task_finished) self.worker.start() def update_status(self, message): self.label.setText(message) def task_finished(self): self.label.setText("任务完成!") self.btn_100ms.setEnabled(True) self.btn_500ms.setEnabled(True) self.worker = None if __name__ == "__main__": app = QApplication(sys.argv) window = MainWindow() window.resize(400, 200) window.show() sys.exit(app.exec_()) ``` ## 关键注意事项 1. **精度问题**: - `time.sleep()` 的实际精度取决于操作系统 - Windows 系统通常精度为15-20毫秒[^1] - Linux/Unix 系统通常精度更高(约1毫秒) 2. **线程安全**: - 所有UI更新必须通过信号/槽机制进行 - 工作线程中直接操作UI会导致不可预测行为 3. **替代方案**: - 对于需要精确计时的场景,考虑使用 `QTimer`: ```python QTimer.singleShot(100, lambda: print("100ms后执行")) ``` 4. **资源管理**: - 长时间运行的线程应实现优雅退出机制 - 使用 `self.isInterruptionRequested()` 检查中断请求 ## 性能对比 | 方法 | 精度 | 跨平台 | 推荐度 | 备注 | |------|------|--------|--------|------| | `time.sleep()` | ★★★☆ | ★★★★★ | ★★★★★ | 毫秒级使用浮点数 | | `QThread.msleep()` | ★★★☆ | ★★★☆☆ | ★★☆☆☆ | Qt 5.8+ 已弃用 | | `QTimer` | ★★★★☆ | ★★★★★ | ★★★★☆ | 更适合定时任务 | ## 相关问题 1. 如何在PyQt5中实现高精度定时器(微秒级)? 2. PyQt5多线程编程中如何安全地终止长时间运行的线程? 3. 使用`QTimer`与工作线程实现定时任务有何区别? 4. 如何避免PyQt5多线程编程中的内存泄漏问题? [^1]: Windows系统的时间精度通常为15.625毫秒(64Hz),这是由系统计时器分辨率决定的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值