C++學習之路(8)——Qt學習—qt共享內存的使用

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

一、QSharedMemory類常用的操作

1、QSharedMemory類對象的創建

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

① 通過構造函數QSharedMemory::QSharedMemory ( const QString & key, QObject * 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 size, AccessMode 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 
#include "dialog.h"
#include

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
//調試用頭文件
#include
#include
#include
#include
#include
#include
#include
#include
#include
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()<#endif
QDataStream in(&buffer); //建立數據流對象,並和緩衝區相關聯
in << image; //向緩衝區寫入數據
int size = buffer.size(); //獲取寫入數據的大小(圖片的大小)
#ifdef DEBUG //調試部分
qDebug()< qDebug()<key();
qDebug()<nativeKey();
// sharememory->setKey("共享內存"); //修改共享內存的關鍵字,將無法訪問共享內存
qDebug()<key();
qDebug()<nativeKey();
qDebug()<
error();
qDebug()<errorString();
#endif
if(true == first_flag)
{
if (!sharememory->create(size)) //創建共享內存,大小為size
{
ui->Label_Display->setText(tr("無法創建共享內存段"));
qDebug()<errorString();
return;
}
first_flag = false;
qDebug()<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)); //顯示圖片
}


分享到:


相關文章: