Qt學習—qt共享內存的使用

Qt提供了QSharedMemory類來訪問共享內存,實現共享內存的操作。

一、QSharedMemory類常用的操作

1、QSharedMemory類對象的創建

利用QSharedMemory類創建實例對象時,必須爲該共享內存指定關鍵字(即爲該共享內存起一個名字)。只有當共享內存被設置了關鍵字之後,纔可以執行創建create()、關聯attach()等操作。爲共享內存指定關鍵字有兩種方法:

① 通過構造函數QSharedMemory::QSharedMemory ( const QString & keyQObject * parent =0 )爲實例對象傳入關鍵字;

例如:

SharedMemory* sharememory;

sharememory = newQSharedMemory("QSharedMemoryExample");

② 通過構造函數QSharedMemory::QSharedMemory (QObject * parent = 0 )構造實例對象,之後調用setKey()函數爲該實例對象設置關鍵字。

例如:

QSharedMemory* sharememory;

sharememory = new QSharedMemory();

sharememory->setKey("QSharedMemoryExample ");


2、創建共享內存

bool QSharedMemory::create int sizeAccessMode mode =ReadWrite )

爲QSharedMemory類實例對象創建一個空間大小爲size的共享內存,該內存空間默認的訪問方式爲可讀可寫。共享內存創建成功返回true,否則返回false。QSharedMemory類定義一個枚舉類變量AccessMode,指定了兩種共享內存的訪問方式:

QSharedMemory::ReadOnly   只讀方式訪問共享內存

QSharedMemory::ReadWrite  讀寫方式訪問共享內存

 

3、關聯共享內存

bool QSharedMemory::attach AccessMode mode =ReadWrite )

將以關鍵字key命名的共享內存和當前程序進行關聯,共享內存默認的訪問方式爲可讀可寫。如果程序和共享內存關聯成功,返回true,否則返回false。

 

4、分離共享內存

bool QSharedMemory::detach ()

解除共享內存和程序的關聯,即調用該函數後,程序不可以再訪問共享內存。如果該共享內存被多個程序實例所關聯,當最後一個程序實例和共享內存解除關聯後,該共享內存將由操作系統自動釋放掉。分離操作成功,返回true。如果返回false,通常意味着該共享內存和程序分離失敗,或者其他程序當前正在訪問該共享內存,分離操作執行失敗。


5、判斷共享內存的關聯狀態

bool QSharedMemory::isAttached ()const

該函數用來判斷程序(調用該函數的程序)是否和共享內存進行關聯,是返回true,否返回false。


6、設置/獲取共享內存的關鍵字

QString QSharedMemory::key ()const                                 //獲取共享內存關鍵字

Qt應用程序通過關鍵字來辨識共享內存。key ()函數用來獲取共享內存的關鍵字,如果沒有指定實例對象的關鍵字,或者共享內存的關鍵字是由nativeKey ()函數指定的話,則返回空。 

void QSharedMemory::setKey (const QString key )        //設定共享內存關鍵字

setKey ()函數用來爲共享內存段設定關鍵字(爲共享內存命名),如果參數key的值和構造函數或者之前指定的關鍵字相同的話,則該函數將不做任何操作,直接返回。

 

7、鎖定/解鎖共享內存

bool QSharedMemory::lock ()                    //鎖定共享內存

如果共享內存資源當前處於釋放狀態,進程調用該函數將共享內存中的資源鎖定,並返回true。其他進程將不能訪問該共享內存。如果共享內存被其他進程佔用時,則該函數會一直處於阻塞狀態,直到其他進程使用完畢,釋放共享內存資源。

bool QSharedMemory::unlock ()         //解鎖共享內存

如果共享內存資源被當前進程所佔有,調用該函數將解鎖該共享資源,並返回true。如果當前進程沒有佔用該資源,或者共享內存被其他進程訪問,則不做任何操作並返回false。

 

爲了保證共享內存中數據的完整性,當一個進程在讀寫共享內存的時候,其他進程不允許對該共享區域進行訪問。QSharedMemory類提供了lock()函數和unlock()函數來實現這一共享內存訪問機制。某一程序對共享內存進行讀寫操作之前,需要調用lock()函數鎖定該共享內存,之後獨享共享內存中的數據,並對數據進行讀寫等操作。共享內存訪問完畢,調用unlock()函數,釋放共享內存的使用權限。


8、錯誤原因

SharedMemoryError QSharedMemory::error ()const 

當共享內存出錯時,調用該函數顯示相應的錯誤代碼。

QString QSharedMemory::errorString ()const

當共享內存出錯時,調用該函數,以文本形式顯示錯誤原因。


9、獲取共享內存的地址

const void *QSharedMemory::constData ()const

void * QSharedMemory::data ()

const void *QSharedMemory::data ()const          //重載函數

程序關聯共享內存的前提下,調用該函數返回共享內存中數據的起始地址。如果沒有關聯共享內存,則返回0。

 

10、獲取共享內存的大小

int QSharedMemory::size ()const

調用該函數將返回程序所關聯的共享內存的大小(字節)。如果沒有關聯的共享內存,則返回0。

 

二、示例代碼

main.cpp源文件

#include <QtGui/QApplication>
#include "dialog.h"
#include <QTextCodec>

int main(int argc, char *argv[])
{
    QApplication application(argc, argv);
    //Qt國際化顯示
    QTextCodec::setCodecForTr(QTextCodec::codecForName("GB18030"));
    QTextCodec::setCodecForLocale(QTextCodec::codecForName("GB18030"));
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("GB18030"));

    Dialog dialog;
    dialog.show();

    return application.exec();
}

dialog.h頭文件

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>

//調試用頭文件
#include <QDebug>
#include <QMessageBox>

#include <QFileDialog>
#include <QDir>
#include <QPixmap>
#include <QImage>
#include <QDataStream>
#include <QBuffer>
#include <QSharedMemory>

namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();
public slots:
    void loadFromFile();        //載入圖片按鈕 響應函數
    void loadFromMemory();      //顯示圖片按鈕 響應函數

private:
    Ui::Dialog *ui;
    QSharedMemory *sharememory; //定義共享內存實例指針
    bool first_flag;            //判斷是否是首次加載文件
};

#endif // DIALOG_H

dialog.cpp源文件

#include "dialog.h"
#include "ui_dialog.h"

#define DEBUG           //調試開關


Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    QObject::connect(ui->PBtn_Load,SIGNAL(clicked()),this,SLOT(loadFromFile()));
    QObject::connect(ui->PBtn_Display,SIGNAL(clicked()),this,SLOT(loadFromMemory()));

    sharememory = new QSharedMemory();              //構造實例對象
    sharememory->setKey("QSharedMemoryExample");    //爲實例對象指定關鍵字(給共享內存命名)
    first_flag = true;
}

Dialog::~Dialog()
{
    delete ui;
}

//載入圖片按鈕響應函數
void Dialog::loadFromFile()
{
    if(sharememory->isAttached())       //檢測程序當前是否關聯共享內存
        sharememory->detach();          //解除關聯
    ui->Label_Display->setText(tr("請選擇一張圖片"));

    QString filename = QFileDialog::getOpenFileName(
                this,"打開",QString(),tr("Image (*.png *.xpm *.jpg)"));
    QImage image;
    if(!image.load(filename))           //將打開的圖片文件和QImage實例關聯
    {
        ui->Label_Display->setText(tr("您選擇的不是圖片文件,請重新選擇"));
        return;
    }
    ui->Label_Display->setPixmap(QPixmap::fromImage(image));

    QBuffer buffer;
    buffer.open(QBuffer::ReadWrite);    //構建並打開數據緩衝區,訪問方式爲讀寫
#ifdef DEBUG
    qDebug()<<"新建緩衝區的大小爲:"<<buffer.size();  //測試緩衝區大小(一般爲0)
#endif

    QDataStream in(&buffer);            //建立數據流對象,並和緩衝區相關聯
    in << image;                        //向緩衝區寫入數據
    int size = buffer.size();           //獲取寫入數據的大小(圖片的大小)

#ifdef DEBUG                             //調試部分
    qDebug()<<"緩衝區的大小爲:"<<size;
    qDebug()<<sharememory->key();
    qDebug()<<sharememory->nativeKey();
//    sharememory->setKey("共享內存");   //修改共享內存的關鍵字,將無法訪問共享內存
    qDebug()<<sharememory->key();
    qDebug()<<sharememory->nativeKey();
    qDebug()<<sharememory->error();
    qDebug()<<sharememory->errorString();
#endif

    if(true == first_flag)
    {
        if (!sharememory->create(size)) //創建共享內存,大小爲size
        {
            ui->Label_Display->setText(tr("無法創建共享內存段"));
            qDebug()<<sharememory->errorString();
            return;
        }
        first_flag = false;
        qDebug()<<sharememory->size();  //顯示共享內存的大小
    }
    //對共享內存進行讀寫操作
    sharememory->lock();        //鎖定共享內存
    char *to = (char*)sharememory->data();      //獲取共享內存中的地址
    const char *from = buffer.data().data();    //獲取有效數據在緩衝區中的地址
    memcpy(to, from, qMin(sharememory->size(), size));  //將緩衝區中的數據複製到共享內存
    sharememory->unlock();      //釋放共享內存
}

//顯示圖片按鈕響應函數
void Dialog::loadFromMemory()
{
    if (!sharememory->attach())     //關聯共享內存
    {
         ui->Label_Display->setText("無法關聯共享內存");
         return;
    }

     QBuffer buffer;                //構建緩衝區
     QDataStream out(&buffer);      //建立數據流對象,並和緩衝區關聯
     QImage image;
     //對共享內存進行讀寫操作
     sharememory->lock();           //鎖定共享內存

     //初始化緩衝區中的數據,setData函數用來初始化緩衝區。
     //該函數如果在open()函數之後被調用,則不起任何作用。
     //buffer.open(QBuffer::ReadOnly);  //解除註釋,則setData函數不起作用,無法加載內存中數據
     buffer.setData((char*)sharememory->constData(), sharememory->size());
     buffer.open(QBuffer::ReadOnly);    //只讀方式打開緩衝區
     out >> image;                      //將緩衝區的數據寫入QImage對象

     sharememory->unlock();         //釋放共享內存

     sharememory->detach();         //解除程序和共享內存的關聯
     ui->Label_Display->setPixmap(QPixmap::fromImage(image));   //顯示圖片
}


 


 



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章