小项目实验:QProcess 管道通讯实验

1.概要

2.内容

以下是一个简单的QProcess管道通信示例,包含两个可执行文件(实际为同一代码),通过命令行参数区分主从进程:

#include "MainWindow.h"

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    MainWindow w;
    w.resize(400, 300);
    w.show();
    return a.exec();
}
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
// main.cpp
#include <QApplication>
#include <QProcess>
#include <QMainWindow>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>
#include <QTextEdit>
#include <QTextStream>
#include <QSocketNotifier>
#include <QLabel>
#include <cstdio>  // 添加缺失的头文件

class MainWindow : public QMainWindow {
    Q_OBJECT
public:
    MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {
        setupUI();
        isChild = QCoreApplication::arguments().contains("--child");

        if (!isChild){
            qDebug() <<"fu";
            startChildProcess();
            setWindowTitle("父进程窗口");
        }
        else{
            qDebug() <<"zi";
            setupChildIO();
            setWindowTitle("子进程窗口");
        }
    }

private:
    QLineEdit *sendEdit;
    QTextEdit *receiveEdit;
    QProcess *process;
    bool isChild;

    void setupUI() {
        QWidget *widget = new QWidget;
        QVBoxLayout *layout = new QVBoxLayout(widget);

        sendEdit = new QLineEdit;
        receiveEdit = new QTextEdit;
        receiveEdit->setReadOnly(true);
        QPushButton *sendBtn = new QPushButton("Send");

        layout->addWidget(new QLabel("Receive:"));
        layout->addWidget(receiveEdit);
        layout->addWidget(new QLabel("Send:"));
        layout->addWidget(sendEdit);
        layout->addWidget(sendBtn);

        connect(sendBtn, &QPushButton::clicked, this, &MainWindow::sendMessage);
        setCentralWidget(widget);
    }

    void startChildProcess() {
        process = new QProcess(this);
        process->start(QApplication::applicationFilePath(), {"--child"});
        connect(process, &QProcess::readyReadStandardOutput, this, [this]{
            receiveEdit->append(process->readAllStandardOutput().trimmed());
        });
    }

    void setupChildIO() {
        qDebug() << "Child process setting up IO...";  // 添加调试
        int fd = fileno(stdin);  // 获取标准输入的文件描述符
        qDebug() << "Child stdin fd:" << fd;           // 确认文件描述符
        QSocketNotifier *notifier = new QSocketNotifier(fd, QSocketNotifier::Read, this);
        connect(notifier, &QSocketNotifier::activated, this, [this]{
            QTextStream in(stdin);  // 正确:使用FILE*指针创建QTextStream
            QString line = in.readLine();
            receiveEdit->append(line);
        });
    }

public slots:
    void sendMessage() {
        QString msg = sendEdit->text();
        sendEdit->clear();

        if (isChild) {
            //QTextStream(stdout) << msg << "\n";  // 正确:使用FILE*指针创建QTextStream
            //stdout->flush();  // 注意这里应使用箭头运算符(实际应为fflush(stdout))
            QTextStream(stdout) << msg << "\n";
            QTextStream(stdout).flush();
        } else {
            if (process->state() == QProcess::Running) {
                process->write(msg.toUtf8() + "\n");
            }
        }
    }
};

#endif // MAINWINDOW_H

 运行结果

代码分析

使用说明:

  1. 编译代码生成可执行文件(如comm_demo
  2. 运行第一个实例:./comm_demo
  3. 运行第二个实例:./comm_demo --child
  4. 在任意窗口的发送框输入消息并点击发送,消息会显示在两个窗口的接收框

实现原理:

  1. 通过--child参数区分主从进程
  2. 主进程使用QProcess启动子进程并建立管道
  3. 主进程通过QProcess的write通道发送消息
  4. 子进程通过QSocketNotifier监听标准输入
  5. 双方均通过标准输出发送消息,通过管道接收消息

注意:实际使用时需要处理编码、消息边界、进程终止等细节,此示例为最小化演示版本。

3.关联链接

4.关联知识

1.QProcess::readyReadStandardOutput

QProcess::readyReadStandardOutput 是 Qt 框架中 QProcess 类提供的一个信号(Signal),其核心功能是通知程序:外部进程的标准输出(Standard Output)有新数据可读。以下是详细解释:


功能解析

  1. 触发条件
    • 当通过 QProcess 启动的外部进程向其标准输出(stdout) 写入数据时,Qt 会自动检测到这一行为。
    • 一旦检测到新数据到达,Qt 会立即触发 readyReadStandardOutput 信号。
  2. 数据流向
    • 外部进程的输出(如 printfcout 等)会被 QProcess 捕获。
    • 数据会先存储在 QProcess 的内部缓冲区中,等待被读取。
  3. 信号作用
    • 该信号的作用是通知程序:此时可以安全地调用 readAllStandardOutput() 或 read() 方法读取数据,而不会阻塞或丢失数据。

核心特性

  • 异步通知:无需轮询(Polling),数据到达时自动触发信号,提高程序效率。
  • 非阻塞设计:与 waitForReadyRead() 等阻塞方法不同,它允许程序在等待数据时继续执行其他操作。
  • 与 readyReadStandardError 区分
    • readyReadStandardOutput 对应标准输出(正常输出)。
    • readyReadStandardError 对应标准错误(错误信息),需单独处理。

典型使用场景

QProcess *process = new QProcess(this);
process->start("your_external_program");


// 连接信号到槽函数
connect(process, &QProcess::readyReadStandardOutput, [=]() {
QByteArray data = process->readAllStandardOutput(); // 读取所有可用数据
QString output = QString::fromUtf8(data).trimmed();
qDebug() << "Received:" << output; // 处理数据
});

注意事项

  1. 数据完整性
    • 输出可能是分多次到达的(如大文件分块传输),需自行处理消息边界(如按行分割或自定义协议)。
    • 示例:使用 \n 作为消息结束符,在槽函数中拼接不完整消息。
  2. 缓冲区管理
    • 未读取的数据会保留在缓冲区中,但建议及时读取以避免内存浪费。
  3. 编码问题
    • 使用 QString::fromUtf8() 或指定正确编码解析数据,避免乱码。

底层机制

  • Qt 通过操作系统提供的管道(Pipe)或伪终端(PTY)捕获子进程输出。
  • 当管道可读时,操作系统触发事件,Qt 内部事件循环检测到后发射信号。

总结

QProcess::readyReadStandardOutput 是实现异步、非阻塞读取外部进程输出的核心机制,适用于需要与外部程序交互的场景(如命令行工具调用、进程间通信)。通过合理处理该信号,可以高效、稳定地实现数据流的控制。

2.QSocketNotifier详解 

QSocketNotifier 是 Qt 框架中用于监控文件描述符(File Descriptor)活动的核心类,尤其在处理套接字(Socket)、管道(Pipe)或文件等底层 I/O 操作时非常有用。它通过事件驱动机制,在文件描述符变为可读、可写或发生异常时触发信号,从而避免阻塞主线程。


核心功能

  1. 监控三种事件类型
    • 可读事件QSocketNotifier::Read):当文件描述符有数据可读时触发。
    • 可写事件QSocketNotifier::Write):当文件描述符可写入数据时触发。
    • 异常事件QSocketNotifier::Exception):当发生错误(如连接断开)时触发。
  2. 信号驱动
    • 当监控的事件发生时,activated(int socket) 信号会被触发,参数为文件描述符。
    • 用户需将此信号连接到自定义的槽函数,处理具体逻辑。

基本用法

1. 创建 QSocketNotifier
int socketFd = /* 获取文件描述符,如套接字、管道等 */;
QSocketNotifier *notifier = new QSocketNotifier(socketFd, QSocketNotifier::Read, this);
connect(notifier, &QSocketNotifier::activated, this, &MyClass::handleSocketEvent);
2. 处理事件
void MyClass::handleSocketEvent(int socketFd) {
    char buffer[1024];
    ssize_t bytesRead = read(socketFd, buffer, sizeof(buffer));
    if (bytesRead > 0) {
        // 处理读取的数据
    } else if (bytesRead == 0) {
        // 连接关闭
    } else {
        // 错误处理
    }
}
3. 启用/禁用监控
notifier->setEnabled(false); // 暂停监控
notifier->setEnabled(true); // 恢复监控

关键特性

1. 线程安全
  • QSocketNotifier 必须在创建它的线程中使用(通常是主线程)。
  • 如果文件描述符活动发生在其他线程,需通过信号槽机制跨线程传递事件。
2. 与 QIODevice 的关系
  • QSocketNotifier 是底层机制,直接操作文件描述符。
  • Qt 的高层类(如 QTcpSocketQLocalSocket)内部可能已封装 QSocketNotifier,无需手动使用。
3. 资源管理
  • 必须确保文件描述符在 QSocketNotifier 生命周期内有效。
  • 删除 QSocketNotifier 前,可调用 setEnabled(false) 停止监控。

典型场景

1. 非阻塞网络编程
// 创建非阻塞套接字
int tcpSocket = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
QSocketNotifier *readNotifier = new QSocketNotifier(tcpSocket, QSocketNotifier::Read, this);
connect(readNotifier, &QSocketNotifier::activated, this, &MyClass::handleTcpData);
2. 进程间通信(IPC)

int pipeFd[2];
pipe(pipeFd);
QSocketNotifier *pipeNotifier = new QSocketNotifier(pipeFd[0], QSocketNotifier::Read, this);
connect(pipeNotifier, &QSocketNotifier::activated, this, &MyClass::handlePipeData);

注意事项

  1. 避免竞争条件
    • 在槽函数中处理 I/O 操作时,确保操作是原子的(如一次性读取所有数据)。
    • 如果操作可能阻塞,考虑使用 QSocketNotifier::Write 监控可写事件,避免忙等待。
  2. 性能优化
    • 频繁启用/禁用 QSocketNotifier 可能影响性能,建议根据实际需求调整。
  3. 错误处理
    • 监控 QSocketNotifier::Exception 事件,及时处理连接断开或错误。

与 select()/poll() 的对比

  • QSocketNotifier 是 Qt 事件循环的集成方案,无需手动管理文件描述符集合。
  • 适合需要与 Qt 信号槽机制深度集成的场景,而 select()/poll() 更灵活但代码更冗长。

总结

QSocketNotifier 是 Qt 中处理底层 I/O 事件的高效工具,尤其适合需要非阻塞操作或与现有非 Qt 代码集成的场景。通过合理使用信号槽和事件循环,可以构建高性能、响应迅速的网络或 IPC 应用。

3.QTextStream(stdout)

QTextStream(stdout) 是 Qt 框架中用于操作标准输出(控制台)的文本流对象,其作用和使用方式如下:

核心解释:

  1. QTextStream
    • Qt 中处理文本流的类,支持读写文本数据(如文件、字符串、标准输入输出)。
    • 提供统一的接口处理不同设备(文件、控制台、网络等)的文本操作。
  2. stdout
    • C/C++ 标准库中的标准输出流(通常对应控制台)。
    • 在 Qt 中,stdout 被封装为 QIODevice 的子类(如 QFile),指向系统的标准输出设备。
  3. 组合作用
    • QTextStream(stdout) 将标准输出流封装为 Qt 的文本流对象,允许使用 Qt 的流操作符(如 <<)和编码设置功能。

示例代码:

#include <QTextStream>


int main() {
    QTextStream out(stdout); // 创建关联到标准输出的文本流
    out.setCodec("UTF-8"); // 设置编码(避免乱码)
    out << "Hello, 世界!" << Qt::endl; // 输出到控制台并换行
    return 0;
}

关键特性:

  1. 统一接口
    • 与操作文件流(如 QFile)的代码风格一致,例如:

      QFile file("output.txt");
      QTextStream fileStream(&file);
      fileStream << "写入文件内容";
  2. 编码控制
    • 通过 setCodec() 设置输出编码(如 UTF-8),解决中文字符乱码问题。
  3. 格式化输出
    • 支持流操作符(<<)链式调用,类似 std::cout
    • 提供 Qt::endl 宏(等同于 \n + 刷新缓冲区)。

对比原生方式:

  • 原生 C++
    std::cout << "Hello, World!" << std::endl;
  • Qt 方式
    QTextStream(stdout) << "Hello, World!" << Qt::endl;
    优势:更灵活的编码设置和跨平台一致性。

注意事项:

  • 直接使用 qInfo() 等宏
    Qt 提供了 qInfo()qWarning()qDebug() 等宏,可直接输出到控制台,无需手动创建 QTextStream
  • 性能
    频繁小数据量输出时,QTextStream 可能略慢于原生 std::cout,但差异通常可忽略。

通过 QTextStream(stdout),开发者能以 Qt 的统一风格操作标准输出,同时获得编码控制等高级功能。

4.stdout详解

stdout 是 C/C++ 标准库中定义的标准输出流,其原理涉及操作系统、文件描述符、缓冲机制等多个层面。以下从底层原理角度详细解释:


1. 文件描述符(File Descriptor)

在 Unix/Linux 系统中,每个进程启动时会自动打开三个标准 I/O 流:

  • stdin (0): 标准输入(键盘)
  • stdout (1): 标准输出(终端/控制台)
  • stderr (2): 标准错误(终端/控制台)

这些流通过文件描述符(整数标识符)与操作系统内核交互。stdout 对应的文件描述符是 1


2. 系统调用与内核交互

当程序向 stdout 写入数据时,底层最终会调用操作系统提供的系统调用(如 write):

// 伪代码示例:向 stdout 写入 "Hello"
write(1, "Hello", 5); // 1 是 stdout 的文件描述符
  • 内核作用:操作系统内核管理所有 I/O 操作,将数据从用户空间复制到内核缓冲区,最终输出到目标设备(如终端)。

3. C 标准库的封装(FILE 结构体)

C 标准库(如 stdio.h)通过 FILE 结构体封装了文件描述符,提供更高级的 I/O 接口:

// stdout 的定义(简化版)
FILE *stdout = &(FILE){
.fd = 1, // 对应文件描述符 1
.buf = buffer, // 内部缓冲区
.buf_size = BUFSIZ,
.mode = _IOWRT // 写模式
};
  • 缓冲机制stdout 默认是行缓冲的(Line Buffered),即遇到换行符 \n 或缓冲区满时,数据才会从用户空间刷新到内核。
    • 示例:printf("Hello"); 可能不会立即输出,但 printf("Hello\n"); 会触发刷新。
    • 手动刷新:fflush(stdout); 强制立即输出。

4. 终端与重定向

  • 终端输出:当 stdout 指向终端时,数据通过终端驱动(如 Linux 的 tty 驱动)处理,支持交互式特性(如光标移动、颜色控制)。
  • 重定向:通过 Shell 的 > 操作符(如 ./program > output.txt),stdout 的文件描述符会被重新指向文件:
    1. Shell 启动程序前,通过 dup2 系统调用将文件描述符 1 指向目标文件。
    2. 程序写入 stdout 时,数据直接写入文件,而非终端。

5. 跨平台抽象(Windows 差异)

  • Windows 系统:没有文件描述符概念,但 C 运行时库(CRT)会模拟类似行为:
    • stdout 对应 CONOUT$ 设备(控制台)。
    • 通过 WriteConsole 或 WriteFile API 实现输出。
  • 跨平台代码:C 标准库(如 stdio.h)隐藏了系统差异,使 printf 和 fprintf(stdout, ...) 在所有平台行为一致。

6. 多线程与同步

  • 线程安全stdout 的写入操作本身是原子性的(单个 printf 调用),但多个线程同时写入可能导致输出交织。
  • 解决方案
    • 使用互斥锁(如 pthread_mutex_t)保护 stdout
    • 或通过 flockfile(stdout) 和 funlockfile(stdout) 实现线程安全。

7. 底层流程总结

  1. 程序调用 printf("Hello")
  2. C 库将数据写入 FILE 结构体的缓冲区。
  3. 遇到 \n 或缓冲区满时,调用 write(1, buffer, size)
  4. 内核将数据复制到内核缓冲区,最终输出到终端或文件。

8. 性能优化

  • 缓冲的意义:减少频繁的系统调用(如每次 printf 都调用 write 会导致性能下降)。
  • 无缓冲模式:通过 setvbuf(stdout, NULL, _IONBF, 0) 禁用缓冲,但会牺牲性能。

通过理解 stdout 的原理,可以更高效地处理 I/O 操作、调试缓冲问题,并深入掌握操作系统与用户程序的交互机制。

5.stdout 是所有进程共享的吗 

stdout 不是所有进程共享的,但多个进程的输出可能最终指向同一个共享资源(如终端或文件)。以下是详细解释:


1. 进程独立性

  • 每个进程独立拥有自己的 stdout
    • 在 Unix/Linux 系统中,每个进程启动时会自动打开三个标准流(stdinstdoutstderr),它们是进程私有的。
    • 这些流通过文件描述符(stdin=0stdout=1stderr=2)与操作系统交互,不同进程的文件描述符是独立的
  • 示例
    • 进程 A 的 stdout 默认指向终端。
    • 进程 B 的 stdout 默认也指向终端。
    • 两者通过终端这一共享资源显示输出,但它们的 stdout 本身是独立的。

2. 输出目标的共享性

  • 默认情况
    • 如果多个进程的 stdout 都指向终端(如直接运行程序),它们的输出会混合显示在终端上,因为终端是共享资源
    • 例如,在终端中同时运行 ./program1 和 ./program2,两者的输出可能交织。
  • 重定向场景
    • 如果将多个进程的 stdout 重定向到同一个文件(如 ./program1 > output.txt & ./program2 >> output.txt),它们的输出会写入同一个文件,因为文件是共享资源
    • 但每个进程的 stdout 本身仍是独立的,只是输出目标被统一配置。

3. 进程间共享 stdout 的特殊场景

  • 通过继承共享
    • 子进程通过 fork() 继承父进程的文件描述符。如果父进程的 stdout 指向某个资源(如文件),子进程会共享同一文件描述符。
    • 示例:
      // 父进程将 stdout 重定向到文件
      freopen("output.txt", "w", stdout);
      if (fork() == 0) {
          // 子进程继承父进程的 stdout(指向 output.txt)
          printf("Child process output\n");
          exit(0);
      }
      // 父进程输出也会写入 output.txt
      printf("Parent process output\n");
  • 通过显式共享
    • 进程间可通过 dup2() 或 shm_open() 等机制共享文件描述符,但这种情况需要显式配置,非默认行为。

4. 关键结论

特性说明
stdout 归属每个进程独立拥有自己的 stdout(文件描述符 1)。
输出目标多个进程的 stdout 可能指向同一个共享资源(如终端、文件),导致输出混合。
共享场景仅当进程通过继承或显式配置共享同一文件描述符时,stdout 才会被共享。

5. 实际影响

  • 输出交织
    • 多个进程独立写入 stdout 时,输出顺序由操作系统调度决定,可能导致内容交错。
    • 解决方案:使用同步机制(如互斥锁)或重定向到独立文件。
  • 资源竞争
    • 如果多个进程同时写入同一文件(通过重定向),需处理文件锁(如 flock())以避免数据损坏。

总结

stdout 本身是进程私有的,但多个进程的输出可能因指向同一共享资源(如终端或文件)而混合。进程间需显式配置才能共享 stdout,否则默认独立。

6.tdout可以用于进行进程间通讯吗 

stdout 可以用于进程间通信(IPC),但通常仅适用于简单场景,且存在显著局限性。以下是详细分析:


1. 通过共享输出目标实现 IPC

  • 原理
    • 若多个进程的 stdout 指向同一共享资源(如文件、管道、终端),则一个进程的输出可被其他进程读取。
    • 示例:通过 Shell 管道 | 连接进程:

      # 进程1的stdout连接到进程2的stdin
      ./process1 | ./process2
  • 实现方式
    • 文件:多个进程将 stdout 重定向到同一文件:
      ./process1 > shared.log & ./process2 > shared.log
    • 管道:通过匿名管道(|)或命名管道(mkfifo)传递数据。
    • 终端:多个进程输出到同一终端,用户手动处理数据。

2. 局限性

局限性说明
无同步机制需自行处理读写顺序和竞争条件(如使用文件锁 flock())。
数据格式依赖输出需是文本或可序列化数据,接收方需能解析。
性能低下频繁小数据量写入/读取效率低,适合低频数据交换。
单向通信stdout 仅支持单向传输(写端),需配合 stdin 实现双向通信。
缓冲区问题行缓冲可能导致数据延迟(需 fflush(stdout) 强制刷新)。

3. 适用场景

  • 简单日志聚合:多个进程将日志写入同一文件。
  • 流水线处理:通过管道 | 连接进程链(如 cat file | grep pattern | sort)。
  • 调试辅助:临时观察多个进程的输出。

4. 更推荐的 IPC 机制

若需可靠、高效的进程间通信,应使用专用机制:

机制适用场景示例
管道(Pipe)父子进程间单向通信pipe() 系统调用
消息队列结构化数据交换msgget()msgsnd()
共享内存高性能数据共享shm_open()mmap()
套接字(Socket)跨网络或本地进程通信socket()bind()
信号(Signal)简单事件通知kill()sigaction()

5. 示例:通过文件实现 IPC

// 进程1:写入共享文件
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main() {
    FILE *fp = fopen("shared.log", "w");
    for (int i = 0; i < 5; i++) {
        fprintf(fp, "Data from process 1: %d\n", i);
        fflush(fp);  // 强制刷新缓冲区
        sleep(1);
    }
    fclose(fp);
    return 0;
}

// 进程2:读取共享文件
#include <stdio.h>
#include <unistd.h>

int main() {
    FILE *fp = fopen("shared.log", "r");
    char buffer[256];
    while (fgets(buffer, sizeof(buffer), fp)) {
        printf("Process 2 received: %s", buffer);
    }
    fclose(fp);
    return 0;
}

结论

  • 可以用于简单 IPC:通过共享 stdout 的输出目标(如文件、管道),但需自行处理同步和性能问题。
  • 不推荐作为主要 IPC 手段:专用 IPC 机制(如管道、消息队列)更高效、可靠。
  • 典型用途:日志聚合、流水线处理等非关键场景。

7.QProcess 管道通信原理

QProcess的管道通信原理基于操作系统提供的进程间通信机制,通过Qt的封装实现了跨平台的异步或同步数据交换。以下是其核心原理的步骤说明:

  1. 管道创建
    当调用QProcess::start()启动外部进程时,Qt内部为子进程的标准输入(stdin)、标准输出(stdout)和标准错误(stderr)分别创建管道。每个管道包含两个文件描述符:父进程的读端和子进程的写端(或反之)。

  2. 流重定向
    子进程启动时,其标准流被重定向到管道的对应端。例如:

    • 子进程的stdout写入到父进程可读的管道写端。
    • 父进程通过读取该管道的读端获取子进程输出。
  3. 数据读写方式

    • 同步模式
      使用waitForReadyRead()等待数据到达,再通过readAllStandardOutput()等函数读取。适用于简单脚本或小数据量场景。
    • 异步模式(推荐)
      通过信号槽机制处理数据。例如,当子进程有数据写入stdout时,触发readyReadStandardOutput信号,父进程连接槽函数实时读取,避免阻塞主线程。
  4. 跨平台抽象
    Qt封装了Unix(pipe()系统调用)和Windows(匿名管道CreatePipe)的差异,开发者无需关心底层实现细节。

  5. 错误处理与生命周期

    • 子进程结束时,触发finished(int exitCode, QProcess::ExitStatus status)信号。
    • 管道关闭或读写错误时,触发errorOccurred(QProcess::ProcessError error)信号,便于调试。

示例代码解析

QProcess process;
process.start("ping", QStringList() << "example.com"); // 启动子进程,自动创建管道

// 异步读取输出(非阻塞)
QObject::connect(&process, &QProcess::readyReadStandardOutput, [&]() {
    QByteArray output = process.readAllStandardOutput();
    qDebug() << "Received:" << output;
});

// 进程结束处理
QObject::connect(&process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
                 [](int exitCode, QProcess::ExitStatus status) {
    qDebug() << "Process exited with code" << exitCode;
});

关键点

  • 非阻塞设计:异步模式通过事件循环(Event Loop)驱动,适合GUI应用避免界面冻结。
  • 缓冲区管理:Qt内部可能使用缓冲区暂存数据,避免频繁系统调用,但需注意及时读取以防止阻塞子进程。
  • 双向通信:通过write()向子进程stdin发送数据(如交互式命令输入),需确保子进程正确读取输入流。

总结
QProcess通过管道实现父子进程间通信,封装了跨平台差异,提供同步/异步API及信号槽机制,简化了进程间数据交换的复杂性,同时保证高效与非阻塞特性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值