QT中的多线程编程

article/2025/9/28 10:00:18

目录

1、QThread的基本使用

2、多线程间的同步 

3、多线程间的互斥 

3.1、线程锁

3.2、死锁

3.3、信号量

3.4、银行家算法的分析与实现

4、线程的生命期问题

4.1、线程的生命期问题 

4.2、同步型线程设计

4.3、异步型线程设计 

5、另一种创建线程的方式(组合)


1、QThread的基本使用

Qt中通过QThread直接支持多线程QThread是一个跨平台的多线程解决方案 ,QThread以简洁易用的方式实现多线程编程 

QThread中的关键成员函数 

void run() :线程体函数,用于定义线程功能(执行流) 

void start() :启动函数,将线程入口地址设置为run函数 

void terminate() :强制结束线程(不推荐),  所有线程都结束后,进程才结束 

#include <QtCore/QCoreApplication>
#include <QThread>
#include <QDebug>class MyThread : public QThread
{
protected:void run() // 线程入口函数{qDebug() << objectName() << " : " << "run() begin";for(int i=0; i<5; i++){qDebug() << objectName() << " : " << i;sleep(1);}qDebug() << objectName() << " : " << "run() end";}
};int main(int argc, char *argv[]) // 主线程入口函数
{QCoreApplication a(argc, argv);qDebug() << "main() begin";MyThread t; // 创建子线程t.setObjectName("t");t.start(); // 启动子线程MyThread tt;tt.setObjectName("tt");tt.start();for(int i=0; i<100000; i++){for(int j=0; j<10000; j++){// 延时, 防止主线程将先于子线程结束 }}qDebug() << "main() end";return a.exec();
}

 在默认情况下,各个线程独立存在,并行执行 

线程的生命周期 

在工程开发中terminate()是禁止使用的,terminate()会使得操作系统暴力终止线程,而不会考虑数据完整性,资源释放等问题! 

在代码中优雅的终止线程 

-run() 函数执行结束是优雅终止线程的唯一方式 

-在线程类中增加标志变量 m_toStop (volatile bool) ,通过m_toStop的值判断是否需要从run()函数返回 

#include <QtCore/QCoreApplication>
#include <QThread>
#include <QDebug>class Sample : public QThread
{
protected:volatile bool m_toStop;void run(){qDebug() << objectName() << " : begin";int* p = new int[10000];for(int i=0; !m_toStop && (i<10); i++){qDebug() << objectName() << " : " << i;p[i] = i * i * i;msleep(500);}delete[] p;qDebug() << objectName() << " : end";}
public:Sample(){m_toStop = false;}void stop(){m_toStop = true;}
};int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);qDebug() << "main begin";Sample t;t.setObjectName("t");t.start();for(int i=0; i<100000; i++){for(int j=0; j<10000; j++){}}t.stop();    // 不会资源泄漏//t.terminate();qDebug() << "main end";return a.exec();
}

2、多线程间的同步 

并发性是多线程编程的本质 ,在宏观上,所有线程并行执行 ,多个线程间相对独立,互不干涉 

在特殊情况下,多线程的执行在时序上存在依赖,所以需要控制多线程间的相对执行顺序。

QThread类直接支持线程间的同步 bool QThread::wait(unsigned long time = ULONG_MAX) 

求和的新解法、并行计算

#include <QtCore/QCoreApplication>
#include <QThread>
#include <QDebug>/*sum(n) => 1 + 2 + 3 + ... + nsum(1000) => ?[1, 1000] =  [1, 300] [301, 600] [601, 1000]*/class Calculator : public QThread
{
protected:int m_begin;int m_end;int m_result;void run(){qDebug() << objectName() << ": run() begin";for(int i=m_begin; i<=m_end; i++){m_result += i;msleep(10);}qDebug() << objectName() << ": run() end";}
public:Calculator(int begin, int end){m_begin = begin;m_end = end;m_result = 0;}void work(){run();}int result(){return m_result;}
};int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);qDebug() << "main begin";Calculator cal1(1, 300);Calculator cal2(301, 600);Calculator cal3(601, 1000);cal1.setObjectName("cal1");cal2.setObjectName("cal2");cal3.setObjectName("cal3");// cal1.work();// cal2.work();// cal3.work();cal1.start();cal2.start();cal3.start();cal1.wait(); // 等待子线程执行结束cal2.wait();cal3.wait();int result = cal1.result() + cal2.result() + cal3.result();qDebug() << "result = " << result;qDebug() << "main end";return a.exec();
}

若没有wait操作,得到的结果是0(三个子线程还没结束就直接获取结果值)

3、多线程间的互斥 

3.1、线程锁

临界资源(Critical Resource) :每次只允许一个线程进行访问(读/写)的资源

线程间的互斥(竞争) :多个线程在同一时刻都需要访问临界资源 

QMutex类是一把线程锁,保证线程间的互斥,利用线程锁能够保证临界资源的安全性 

QMutex中的关键成员函数 

  -void lock() 

      • 当锁空闲时,获取锁并继续执行 

      • 当锁被获取阻塞并等待锁释放 

  -void unlock() 

      • 释放锁(同一把锁的获取和释放锁必须在同一线程中成对出现) 

      • 注意: 如果 mutex 在调用 unlock() 时处于空闲状态,那么程序的行为是未定义的!

生产消费者问题 

有n个生产者同时制造产品,并把产品存入仓库中 ;有m个消费者同时需要从仓库中取出产品 

规则: 当仓库未满,任意生产者可以存入产品 ;当仓库未空,任意消费者可以取出产品 

#include <QtCore/QCoreApplication>
#include <QThread>
#include <QMutex>
#include <QDebug>static QMutex g_mutex;  // 线程锁
static QString g_store; // 仓库class Producer : public QThread
{
protected:void run(){int count = 0;while(true){g_mutex.lock();g_store.append(QString::number((count++) % 10));qDebug() << objectName() << " : " + g_store;g_mutex.unlock();msleep(1);}}
};class Customer : public QThread
{
protected:void run(){while( true ){g_mutex.lock();if( g_store != "" ){g_store.remove(0, 1);qDebug() << objectName() << " : " + g_store;}g_mutex.unlock();msleep(1);}}
};int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);Producer p;Customer c;p.setObjectName("Producer");c.setObjectName("Customer");p.start();c.start();return a.exec();
}

一般性原则 :每一个临界资源都需要一个线程锁进行保护! 

3.2、死锁

死锁示例

#include <QtCore/QCoreApplication>
#include <QThread>
#include <QMutex>
#include <QDebug>QMutex g_mutex_1;
QMutex g_mutex_2;class ThreadA : public QThread
{
protected:void run(){while( true ){g_mutex_1.lock();qDebug() << objectName() << "get m1";g_mutex_2.lock();qDebug() << objectName() << "get m2";qDebug() << objectName() << "do work ...";g_mutex_2.unlock();g_mutex_1.unlock();sleep(1);}}
};class ThreadB : public QThread
{
protected:void run(){while( true ){g_mutex_2.lock();qDebug() << objectName() << "get m2";g_mutex_1.lock();qDebug() << objectName() << "get m1";qDebug() << objectName() << "do work ...";g_mutex_1.unlock();g_mutex_2.unlock();sleep(1);}}
};int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);ThreadA ta;ThreadB tb;ta.setObjectName("ta");tb.setObjectName("tb");ta.start();tb.start();return a.exec();
}

线程的死锁概念 :线程间相互等待临界资源而造成彼此无法继续执行 

发生死锁的条件 

-系统中存在多个临界资源且临界资源不可抢占(每次只能给一个线程使用)

-线程需要多个临界资源才能继续执行 

-产生死锁有四个必要条件:互斥、请求与保持、不可剥夺、循环等待  (必要条件即满足不一定发生)

死锁的避免 (破坏四个条件)

方法一:资源有序分配法(破坏循环等待)

        -对所有的临界资源都分配一个唯一的序号(r1,r2,rn) 

        -对应的线程锁也分配同样的序号(m1, m2 , mn) 

        -系统中的每个线程按照严格递增的次序请求资源 

3.3、信号量

信号量是特殊的线程锁 ,信号量允许N个线程同时访问临界资源,Qt中直接支持信号量(QSemaphore) 

QSemaphore使用示例 

QSemaphore对象中维护了一个整型值 ,acquire()使得该值减1 , release()使得该值加1 ,当该值为0时,acquire()函数将阻塞当前线程 

再论生产消费者问题    main.cpp

#include <QtCore/QCoreApplication>
#include <QThread>
#include <QSemaphore>
#include <Qdebug>const int SIZE = 5;
unsigned char g_buff[SIZE] = {0}; QSemaphore g_sem_free(SIZE); // 5个可生产资源
QSemaphore g_sem_used(0);    // 0个可消费资源// 生产者生产产品
class Producer : public QThread
{
protected:void run(){while( true ){int value = qrand() % 256;// 若无法获得可生产资源,阻塞在这里g_sem_free.acquire();for(int i=0; i<SIZE; i++){if( !g_buff[i] ){g_buff[i] = value;qDebug() << objectName() << " generate: {" << i << ", " << value << "}";break;}}// 可消费资源数+1g_sem_used.release();sleep(2);}}
};
// 消费者消费产品
class Customer : public QThread
{
protected:void run(){while( true ){// 若无法获得可消费资源,阻塞在这里g_sem_used.acquire();for(int i=0; i<SIZE; i++){if( g_buff[i] ){int value = g_buff[i];g_buff[i] = 0;qDebug() << objectName() << " consume: {" << i << ", " << value << "}";break;}}// 可生产资源数+1g_sem_free.release();sleep(1);}}
};int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);Producer p1;Producer p2;Producer p3;p1.setObjectName("p1");p2.setObjectName("p2");p3.setObjectName("p3");Customer c1;Customer c2;c1.setObjectName("c1");c2.setObjectName("c2");p1.start();p2.start();p3.start();c1.start();c2.start();return a.exec();
}

3.4、银行家算法的分析与实现

研究一个银行家如何将总数一定的资金,安全地借给若干个顾客,使顾客既能满足对资金的需求,也使银行家可以收回自己的全部资金,不至于破产。 

算法策略 :银行优先分配资源给最小需求的客户

应用场景 :操作系统内核中的进程管理 ;数据库内核中的频繁事务管理 

Qt中的算法实现方案 

          -使用多线程机制模拟客户和银行 

         -银行优先分配资源给最小需求的客户

          -当客户的资源需求无法满足的时候 , 收回已分配的资源 ,强制结束线程

银行家算法的实现   main.cpp

#include <QtCore/QCoreApplication>
#include <QThread>
#include <QMutex>
#include <QList>
#include <QDebug>class Customer : public QThread 
{
protected:int m_need;             // 当前顾客所需资金总额volatile int m_current; // 手中目前已有资金,临界资源QMutex m_mutex;void run(){bool condition = false;qDebug() << objectName() << "begin to apply money";do{m_mutex.lock();condition = (m_current < m_need); // 手中资金比所需资金少,等银行放款m_mutex.unlock();msleep(10);}while( condition );qDebug() << objectName() << "end (get enough money)";}
public:Customer(int current, int need){m_current = current;m_need = need;}void addMoney(int m){m_mutex.lock();m_current += m;m_mutex.unlock();}int backMoney(){int ret = 0;m_mutex.lock();ret = m_current;m_current = 0;m_mutex.unlock();return ret;}int current(){int ret = 0;m_mutex.lock();ret = m_current;m_mutex.unlock();return ret;}int need(){return m_need;}
};class Bank : public QThread
{
protected:QList<Customer*> m_list;  // 等待放款的客户int m_total;              // 银行库存资金数void run(){int index = -1;qDebug() << objectName() << " begin: " << m_total;do{index = -1;// 若顾客资金已满足需求,收回钱for(int i=0; i<m_list.count(); i++) {if( m_list[i]->current() == m_list[i]->need() ){qDebug() << objectName() << " take back money from " << m_list[i]->objectName() << " " << m_list[i]->need();m_total += m_list[i]->backMoney();}}qDebug() << objectName() << " current: " << m_total;// 找资金需求量最小客户,得到下标与所需资金int toGet = 0x00FFFFFF;for(int i=0; i<m_list.count(); i++){if( m_list[i]->isRunning() ){int tmp = m_list[i]->need() - m_list[i]->current();if( toGet > tmp ){index = i;toGet = tmp;}}}if( index >=0 ){// 资金需求量最小客户所需资金小于银行库存资金,放款if( toGet <= m_total ){qDebug() << objectName() << " give money to: " << m_list[index]->objectName();m_total--;m_list[index]->addMoney(1); // 每次放款1单位}else{qDebug() << objectName() << " terminate: " << m_list[index]->objectName();m_total += m_list[index]->backMoney();  // 结束贷款,收回钱m_list[index]->terminate();}}sleep(1);}while( index >= 0 );qDebug() << objectName() << " end: " << m_total;}
public:Bank(int total){m_total = total;}void addCustomer(Customer* customer){m_list.append(customer);}
};int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);Customer p(4, 8);Customer q(2, 3);Customer r(2, 11); Bank bank(2);p.setObjectName("P");q.setObjectName("Q");r.setObjectName("R");bank.setObjectName("Bank");bank.addCustomer(&p);bank.addCustomer(&q);bank.addCustomer(&r);p.start();q.start();r.start();bank.start();return a.exec();
}


4、线程的生命期问题

4.1、线程的生命期问题 

C++对象有生命周期; 线程也有生命周期; QThread对象的生命周期对应的线程生命周期是否一致?

准则 :  线程对象生命期必须大于对应线程生命期 ,遵守这个准则可以避免很多问题

下面代码的问题: 局部对象t在start后就会被销毁,同时成员变量 i 也会被销毁,然而线程还在运行,非法访问已经被销毁的变量

4.2、同步型线程设计

同步型线程设计

    -概念 :线程对象主动等待线程生命期结束后才销毁 

    -特点 :同时支持在栈和堆中创建线程对象 ,对象销毁时确保线程生命期结束 

    -要点 :在析构函数中先调用wait()函数,强制等到线程运行结束 

    -使用场合 :线程生命期相对较短的情形

SyncThread.h

#ifndef SYNCTHREAD_H
#define SYNCTHREAD_H#include <QThread>class SyncThread : public QThread
{Q_OBJECTprotected:void run();public:explicit SyncThread(QObject *parent = 0);~SyncThread();
};#endif // SYNCTHREAD_H

SyncThread.cpp

#include "SyncThread.h"
#include <QDebug>SyncThread::SyncThread(QObject *parent) :QThread(parent)
{
}void SyncThread::run()
{qDebug() << "void SyncThread::run() tid = " << currentThreadId();for(int i=0; i<3; i++){qDebug() << "void SyncThread::run() i = " << i;sleep(1);}qDebug() << "void SyncThread::run() end";
}SyncThread::~SyncThread()
{wait(); // 等待线程结束才析构qDebug() << "SyncThread::~SyncThread() destroy thread object";
}

main.cpp

#include <QtCore/QCoreApplication>
#include <QDebug>
#include "SyncThread.h"void sync_thread()
{SyncThread st;st.start();
}int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);qDebug() << "main() tid = " << QThread::currentThread();sync_thread();return a.exec();
}

4.3、异步型线程设计 

异步型线程设计 

    -概念 :线程生命期结束时通知销毁线程对象 

    -特点 :只能在中创建线程对象 ,线程对象不能被外界主动销毁 

    -要点 :在 run() 中最后调用 deleteLater() 函数 ,线程体函数主动申请销毁线程对象 

    -使用场合 :线程生命期不可控,需要长时间运行于后台的情形

AsyncThread.h

#ifndef ASYNCTHREAD_H
#define ASYNCTHREAD_H#include <QThread>class AsyncThread : public QThread
{Q_OBJECTprotected:void run();explicit AsyncThread(QObject *parent = 0); // 只能在堆空间创建对象~AsyncThread(); // 禁用deletepublic:static AsyncThread* NewInstance(QObject *parent = 0);};#endif // ASYNCTHREAD_H

AsyncThread.cpp

#include "AsyncThread.h"
#include <QDebug>AsyncThread* AsyncThread::NewInstance(QObject *parent)
{return new AsyncThread(parent);
}AsyncThread::AsyncThread(QObject *parent) :QThread(parent)
{
}void AsyncThread::run()
{qDebug() << "void AsyncThread::run() tid = " << currentThreadId();for(int i=0; i<3; i++){qDebug() << "void AsyncThread::run() i = " << i;sleep(1);}qDebug() << "void AsyncThread::run() end";deleteLater(); // 通知销毁当前线程对象 void QObject::deleteLater () [slot]
}AsyncThread::~AsyncThread()
{qDebug() << "AsyncThread::~AsyncThread() destroy thread object";
}

main.cpp

#include <QtCore/QCoreApplication>
#include <QDebug>
#include "AsyncThread.h"void async_thread()
{AsyncThread* at = AsyncThread::NewInstance();at->start();
}int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);qDebug() << "main() tid = " << QThread::currentThread();async_thread();return a.exec();
}


5、另一种创建线程的方式(组合)

历史的痕迹

     -面向对象程序设计实践的早期,工程中习惯于通过继承的方式扩展系统的功能

     -早期的Qt版本只能通过继承的方式创建线桯 ,通过继承的方式实现多线程没有任何实际意义,尽量避免重写void run() 

     -现代软件技术提倡以组合的方式代替继承 

class QThread : public QObject
{//...protected: virtual void run() = 0;  // 必须子类实现//...
} 

现代软件架构技术 

     -参考准则: 尽量使用组合的方式实现系统功能,代码中仅体现需求中的继承关系 

                         除了重写的run不同,其它接口完全相同

QThread类的改进 

class QThread : public QObject
{//...protected: virtual void run() // 新版本QT{(void)exec();  // 默认开启事件循环}//...
} 

如何灵活的指定一个线程对象的线程入口函数? 

解决方案-信号与槽 

       1. 在类中定义一个槽函数 void tmain() 作为线程入口函数 

       2. 在类中定义一个 QThread 成员对象 m_thread 

       3. 改变当前对象的线程依附性到 m_thread 

       4 连接 m_thread 的 start() 信号到 tmain() 

AnotherThread.h

#ifndef ANOTHERTHREAD_H
#define ANOTHERTHREAD_H#include <QObject>
#include <QThread>class AnotherThread : public QObject
{Q_OBJECTQThread m_thread;
protected slots:void tmain(); // 线程入口函数
public:explicit AnotherThread(QObject *parent = 0);void start();void terminate();void exit(int c);~AnotherThread();};#endif // ANOTHERTHREAD_H

AnotherThread.cpp

#include "AnotherThread.h"
#include <QDebug>AnotherThread::AnotherThread(QObject *parent) :QObject(parent)
{moveToThread(&m_thread);connect(&m_thread, SIGNAL(started()), this, SLOT(tmain()));
}void AnotherThread::tmain()
{qDebug() << "void AnotherThread::tmain() tid = " << QThread::currentThreadId();for(int i=0; i<10; i++){qDebug() << "void AnotherThread::tmain() i = " << i;}qDebug() << "void AnotherThread::tmain() end";m_thread.quit();
}void AnotherThread::start()
{m_thread.start(); // m_thread线程开启,定义的tmain函数被调用(run函数也被调用,开启事件循环)
}void AnotherThread::terminate()
{m_thread.terminate();
}void AnotherThread::exit(int c)
{m_thread.exit(c);
}AnotherThread::~AnotherThread()
{m_thread.wait(); // 同步设计
}

main.cpp

#include <QtCore/QCoreApplication>
#include <QDebug>
#include <QThread>
#include "AnotherThread.h"void test()
{AnotherThread at;at.start();
}int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);qDebug() << "main() tid = " << QThread::currentThreadId();test();return a.exec();
}

                                 


http://chatgpt.dhexx.cn/article/8KakOADY.shtml

相关文章

【QT开发入门】

https://blog.csdn.net/fuhanghang/article/details/123517493 目录 QT新建项目的五类模板Qt应用程序拥有4个子模版&#xff1a;三个基类 QT新建项目的五类模板 Appliacation:QT的应用程序&#xff0c;包含Qt Quick和普通窗口程序Library&#xff1a;它可以创建动态库、静态库…

C++/Qt编程规范

文章目录 一、头文件规范二、变量命名三、信号和槽四、注释 一、头文件规范 在编码中对头文件的引用&#xff0c;建议按照以下顺序进行&#xff1a; 1)类定义头文件 2)其他库头文件 a)Qt模块头文件 b)XTAL平台框架模块头文件 c)第三方库头文件 d)自定义公共库头文件 二、变量…

13.QT实战编程

mingw推荐中文乱码使用 pro 类似于vs开发中有个.sln 双击之后项目就可以打开了 5版本以上多了一个QtWidgets模块 防止头文件重复包含 帮助文档&#x1f446; 没有智能提示&#xff0c;因为没有包含类的头文件 this指向当前的指针 中文正常显示是因为 UTF-8 创建对象的时候…

qt串口编程

第一步在pro文件加入&#xff1a; QT serialport代码如下&#xff1a;QT core gui QT serialportgreaterThan(QT_MAJOR_VERSION, 4): QT widgetsCONFIG c11# The following define makes your compiler emit warnings if you use # any Qt feature that has be…

Qt基础编程

什么是Qt Qt就是c的一种跨操作系统平台的可视化开发工具 qt5.15.2的下载 下载安装链接 安装过程中出现network error while......时的解决办法 创建项目 application是什么 application应用程序 作用 QApplication---界面应用入口 也就是 只要是要建立界面的QT项目都需…

Qt入门使用Qt编写程序详细全过程

1、 双击打开Qt 2、 点击文件&#xff08;F&#xff09; 3、 选择新建文件或项目 4、 选择Application 5、 选择Qt Widgets Application 6、 点击choose 7、 输入项目名称&#xff08;英文&#xff09; 8、 点击下一步 9、 点击下一步 10、 点击完成 11、 一个没有…

Qt编程基础:认识常用的基本类型

前言 上一节已经成功创建了一个Qt项目&#xff0c;接下来就是要在创建好的项目中&#xff0c;添加自己想要的功能。在写代码之前&#xff0c;我们需要掌握Qt的一些基础知识。 语法部分就不用讲了&#xff0c;这系列文章是对有C或C语言基础的同学展开的&#xff0c;如果一点编…

[QT入门篇]编程基础知识

一、坐标体系 在 Qt 中窗口的显示是需要指定位置的&#xff0c;这个位置是通过坐标来确定的&#xff0c;所有坐标的选取都是基于坐标原点来确定的&#xff0c;Qt的坐标原点在窗口的左上角。 在一个 Qt 窗口中一般都有很多子窗口内嵌到这个父窗口中&#xff0c;其中每个窗口都有…

QT高级编程之QT基本概览

QT高级编程 主要从以下几个方面来介绍QT高级编程&#xff0c;并介绍QT相关的概念。 1、 QT部件Widget&#xff1b; 2、 QT信号与槽机制&#xff1b; 3、 对象树关系&#xff1b; 4、 布局管理&#xff1b; 5、标准对话框以及自定义对话框&#xff1b; 6、文件与目录&#xff…

QT5编程入门教程(非常详细)

Qt 是一个跨平台的 C 框架&#xff08;C库&#xff09;&#xff0c;目前最新的版本是 Qt5。Qt5 还包含了很多小版本&#xff0c;其中推荐 Qt5.6 或 Qt5.9&#xff0c;这两个版本是 LTS 版本&#xff08;即长期支持版本&#xff09;&#xff0c;Bug较少&#xff0c;相对稳定。 Q…

取模和与运算的一点关系

与n取模其实就是和n-1相与 当然是在二进制基础上 在HashMap的 先高16位异或低16位再取模运算 取模运算转化成位运算公式:a%(2^n) 等价于 a&(2^n-1),而&操作比%操作具有更高的效率

负数的与运算

计算机中的位运算是基于补码的。正数的原码反码补码相同&#xff0c;而负数有一些差别。 如&#xff1a; 7的补码为0111 -7的补码为1001。其计算过程为先算出7的原码0111&#xff0c;按位取反得1000&#xff0c;在加上1得1001。这个步骤也是其他负数计算补码的方式。 示例&…

数与运算

数学是研究数与运算的一门科学&#xff0c;数和运算都是人类根据自然界的客观规律抽象出来的&#xff0c;人们利用抽象的假定去研究更高层次客观规律&#xff0c;再利用这些客观规律解决自然界中出现的问题&#xff0c;这就是数学学科的用途。 数学中的数由什么组成的&#xff…

C/C++:与运算、或运算、异或运算、指针

前言忘记进制的同学先看这里&#xff1a; 十进制数&#xff0c;没有前缀 二进制数&#xff0c;前缀是0b 八进制数&#xff0c;前缀是0o 十六进制数&#xff0c;前缀是0xlet decimalInteger 17 let binaryInteger 0b10001 // 二进制的17 let octalInteger 0o21 …

“”是什么含义?与运算入门级讲解;什么是与运算?

与运算&#xff08;AND&#xff09;是计算机中最基础、最常用的一种逻辑运算&#xff0c;也被称为按位与&#xff08;Bitwise AND&#xff09;运算。它是指在二进制数中&#xff0c;对两个二进制数的每一位进行逻辑与操作&#xff0c;只有当两个二进制数的对应位都为1时&#x…

数字电路三种基本逻辑运算关系:与运算、或运算、非运算

1、基本概念 1.逻辑常量与变量&#xff1a;逻辑常量只有两个&#xff0c;即0和1&#xff0c;用来表示两个对立的逻辑状态。逻辑变量与普通代数一样&#xff0c;也可以用字母、符号、数字及其组合来表示&#xff0c;但它们之间有着本质区别&#xff0c;因为逻辑变量的取值只…

二进制与运算、或运算、非运算

与运算 "与"运算是计算机中一种基本的逻辑运算方式&#xff0c;符号表示为&&#xff0c;运算法则为遇0得0。也就是说只要有0&#xff0c;结果即为0。 举例 或运算 "或"运算符号表示为|&#xff0c;运算法则为遇1得1。也就是说只要有1&#xff0c;结…

​二进制运算符:(与运算)、|(或运算)、~(取反运算)、^(异或运算)、位移运算符​

说明 所有的位运算符操作的都是二进制&#xff0c;而不是我们日常生活中常用的十进制。 在系统中&#xff0c;一个字节占8位。 按位与运算符&#xff08;&&#xff09; 参加运算的两个数据&#xff0c;按二进制位进行“与”运算。 运算规则&#xff1a;如果两个二进制…

第三章 运算方法与运算器

文章目录 定点补码加减法运算补码加减法运算方法溢出及检测溢出检测操作数与运算结果的符号位是否一致最高位的进位和符号位的进位是否一致变形补码 补码加减法的逻辑实现 移码加减运算及实现逻辑移码的加法运算移码加减法的溢出判断直接采用移码运算的溢出判断方法采用双符号判…

2019做报表用什么软件:报表类型,产品推荐

在大数据时代&#xff0c;报表可以帮助我们从海量数据中挖掘有用的数据&#xff0c;选择软件做什么就变得尤为重要。选择什么类型的软件进行报表?推荐哪些报表产品?本文请一位专业的数据分析师&#xff0c;介绍选择报表软件的经验。 ……阅读更多&#xff0c;请戳原文链接&am…