The read() and write() are blocking I/O, If your source use the system function read() or write() to access the filesystem that they will actually launch the io system call.
The fread() and fwrite() are user-buffered I/O. The data will keep in the buffer until the data size is filled with the block size then they will launch the real io system call
Experiment with Blocking I/O
write.c
--
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd;
int i;
char c = 'a';
fd = open("data.xxx", O_CREAT | O_WRONLY | O_TRUNC);
for(i = 0; i < 4096; ++i)
write(fd, &c, 1);
close(fd);
}
strace -c -e trace=write ./write
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
100.00 0.012361 3 4096 write
------ ----------- ----------- --------- --------- ----------------
100.00 0.012361 4096 total
read.c
--
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd;
int i;
char c = 'a';
fd = open("data.xxx", O_RDONLY);
while(read(fd, &c, 1));
close(fd);
}
strace -c -e trace=read ./read
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
100.00 0.020256 5 4098 read
------ ----------- ----------- --------- --------- ----------------
100.00 0.020256 4098 total
User-Buffered IO
fwrite.c
--
#include <stdlib.h>
#include <stdio.h>
int main()
{
FILE *fp;
int i;
char c = 'a';
fp = fopen("data.xxx", "w");
for(i = 0; i < 4096; ++i)
fwrite(&c, 1, 1, fp);
fclose(fp);
}
strace -c -e trace=write ./fwrite
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
100.00 0.000004 4 1 write
------ ----------- ----------- --------- --------- ----------------
100.00 0.000004 1 total
#include <stdlib.h>
#include <stdio.h>
int main()
{
FILE *fp;
int i;
char c = 'a';
fp = fopen("data.xxx", "r");
while(fread(&c, 1, 1, fp));
fclose(fp);
}
strace -c -e trace=read ./fread
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
100.00 0.000009 3 3 read
------ ----------- ----------- --------- --------- ----------------
100.00 0.000009 3 total
慢半拍
2014年4月25日 星期五
2014年4月22日 星期二
Linux PIP wirte and read
By the linux implementaion, the WRITE PROCESS can write max data into the PIP is 64Kbytes if there are no process reads(consumes) data from the PIP then the WRITE PROCESS will block in write(), after the READ PROCESS reads(consumes) data more than 4KBytes from PIP then the WRITE PROCESS will wirte data into the PIP again to fill the data consumed by READ PROCESS, else the WRITE PRCESS still block in wirte() if the READ PROCESS reads(consumes) data less than 4KBytes.
Ex:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
int main()
{
pid_t pid;
int pipfd[2] = {0};
if(pipe(pipfd) < 0) {
printf("pipe() ... fail\n");
exit(0);
}
if((pid = fork()) == 0) {
char *buf = "0123456789";
int cnt = 1;
close(pipfd[0]);
while(1) {
printf(" Write ==========> PIP: cnt:%d \n", cnt++);
//write(pipfd[1], buf, strlen(buf));
write(pipfd[1], buf, 1);
}
} else {
char buf[512];
int count = 1;
sleep(30);
close(pipfd[1]);
while(1){
read(pipfd[0], &buf, sizeof(buf));
printf(" PIP ==========> Read(): cnt:%d \n", count++);
sleep(1);
}
}
return 0;
}
2013年11月13日 星期三
The udev and dbus in the root jail environment.
The root jail system lives in the base system that both UDev systems will receive the kernel notification from the netlink so you need to take care about race condition like upload firmware etc..., but the DBus system (system bus) will stay in isolation space because it used the unix socket to make communication but the system bus' unix socket must be take care. If you use mount bind to bind used folder form Base system to root jail system that the system_bus_socket can't be located at the same path.
2013年10月30日 星期三
DBus Notes
- DBus 是一個 IPC System ,分為兩種型態 System Bus 與 Session Bus。
- Session Bus 提供 applications 之間互相溝通, 在系統上 Session Bus 可以有多可, 一個 Session 就是一個 Group。
- System Bus 整個系統只能有一個 System Bus,有些資料說到 System Bus 可以透過 kobject(netlink) 與 kernel 溝通。 但實際上從 dbus 的 source code(version 1.6.8 kubutu 13.04) 裡並無看到任何使用 netlink 部分。 我想 System Bus 主要是以 root 權限啟動在整個系統裡只有一個且是全域所以稱之為 System Bus, 與 kernel 溝通(控制硬體)的部分我想是透過 system layer 的 applications 如 udev, NetworkManager, UPower etc... , 並非直接透過 netlink。在其他文件中有提到 dbus 以實踐在 linux kernel 裡但這部分目前無相關資料。
2013年10月24日 星期四
Udev 與 devtmpfs 的關係
Driver Core: devtmpfs - kernel-maintained tmpfs-based /dev
Devtmpfs lets the kernel create a tmpfs instance called devtmpfs very early at kernel initialization, before any driver-core device is registered. Every device with a major/minor will provide a device node in devtmpfs.
Devtmpfs can be changed and altered by userspace at any time, and in any way needed - just like today's udev-mounted tmpfs. Unmodified udev versions will run just fine on top of it, and will recognize an already existing kernel-created device node and use it. The default node permissions are root:root 0600. Proper permissions and user/group ownership, meaningful symlinks, all other policy still needs to be applied by userspace.
If a node is created by devtmps, devtmpfs will remove the device node when the device goes away. If the device node was created by userspace, or the devtmpfs created node was replaced by userspace, it will no longer be removed by devtmpfs.
If it is requested to auto-mount it, it makes init=/bin/sh work without any further userspace support. /dev will be fully populated and dynamic, and always reflect the current device state of the kernel. With the commonly used dynamic device numbers, it solves the problem
where static devices nodes may point to the wrong devices.
It is intended to make the initial bootup logic simpler and more robust, by de-coupling the creation of the inital environment, to reliably run userspace processes, from a complex userspace bootstrap logic to provide a working /dev.
Devtmpfs can be changed and altered by userspace at any time, and in any way needed - just like today's udev-mounted tmpfs. Unmodified udev versions will run just fine on top of it, and will recognize an already existing kernel-created device node and use it. The default node permissions are root:root 0600. Proper permissions and user/group ownership, meaningful symlinks, all other policy still needs to be applied by userspace.
If a node is created by devtmps, devtmpfs will remove the device node when the device goes away. If the device node was created by userspace, or the devtmpfs created node was replaced by userspace, it will no longer be removed by devtmpfs.
If it is requested to auto-mount it, it makes init=/bin/sh work without any further userspace support. /dev will be fully populated and dynamic, and always reflect the current device state of the kernel. With the commonly used dynamic device numbers, it solves the problem
where static devices nodes may point to the wrong devices.
It is intended to make the initial bootup logic simpler and more robust, by de-coupling the creation of the inital environment, to reliably run userspace processes, from a complex userspace bootstrap logic to provide a working /dev.
早期的作法應該是先建立一份 static /dev 提供系統 booting 時使用,當系統 booting 完成後再掛載 tmpfs 到 /dev 上.由 udevadm 重新 trigger kernel,再用 udev 動態建立相對應的 device node 在 /dev 裡
在 linux kernel 2.6.32 後使用 devtmpfs 之後. Udev 並不負責 create device node. create device node 的工作則是交由 Kernel 的 devtmpfs 負責. Udev 則是負責接收 kernel 送出的 uevent 依照相對的資訊如 device ID product ID,去載入相對應的 kernel module,device node的權限管理(參照上述藍色註記部分 device node 被 devtmpfs 建立出來的 default 屬性是 root:root 0660) 與建立相對應的 symlink file etc.
**注意舊版的 udev 會做 device node的建立,新版本的則不會只會做 symlink
http://www.freedesktop.org/software/systemd/
http://ftp.sunet.se/pub/Linux/kernel.org/linux/utils/kernel/hotplug/
**注意舊版的 udev 會做 device node的建立,新版本的則不會只會做 symlink
http://www.freedesktop.org/software/systemd/
http://ftp.sunet.se/pub/Linux/kernel.org/linux/utils/kernel/hotplug/
2013年9月23日 星期一
裝飾者模式(Decorator Pattern)
裝飾者模式功能在於動態擴充,動態地將責任加諸於物件上。想要擴充功能,裝飾者提供有別於繼承的另一個選擇。
- 繼承屬於擴充形式之一,但不見得是達到彈性設計的最佳方式。
- 在我們的設計中,應該允許行為可以被擴充,而無須修改計有的程式碼。
- 合成與委派可時常在執行時期,動態的加上新的行為。
- 除了繼承,裝飾者模式也可以讓我們擴充行為。
#include <stdlib.h>
#include <stdio.h>
class CComponent
{
public:
CComponent()
{
printf("%s\n", __PRETTY_FUNCTION__);
}
virtual ~CComponent()
{
printf("%s\n", __PRETTY_FUNCTION__);
}
virtual int value(void) = 0;
};
class CConcreteComponent : public CComponent
{
private:
int val;
public:
CConcreteComponent()
{
val = 10;
printf("%s\n", __PRETTY_FUNCTION__);
}
virtual ~CConcreteComponent()
{
printf("%s\n", __PRETTY_FUNCTION__);
}
virtual int value(void)
{
printf("%s\n", __PRETTY_FUNCTION__);
return val;
}
};
class CDecorator : public CComponent
{
public:
CDecorator()
{
printf("%s\n", __PRETTY_FUNCTION__);
}
virtual ~CDecorator()
{
printf("%s\n", __PRETTY_FUNCTION__);
}
// 加上新的行為
virtual void method(void) = 0;
};
class CConcreteDecoratorA : public CDecorator
{
private:
CComponent *component;
public:
CConcreteDecoratorA(CComponent *c) : component(c)
{
printf("%s\n", __PRETTY_FUNCTION__);
}
virtual ~CConcreteDecoratorA()
{
printf("%s\n", __PRETTY_FUNCTION__);
delete component;
}
virtual void method(void)
{
}
// 將原生物件因裝飾後加入新的行為
virtual int value(void)
{
printf("%s\n", __PRETTY_FUNCTION__);
return 20 + component->value();
}
};
class CConcreteDecoratorB : public CDecorator
{
private:
CComponent *component;
public:
CConcreteDecoratorB(CComponent *c) : component(c)
{
printf("%s\n", __PRETTY_FUNCTION__);
}
virtual ~CConcreteDecoratorB()
{
printf("%s\n", __PRETTY_FUNCTION__);
delete component;
}
virtual void method(void)
{
}
// 將原生物件因裝飾後加入新的行為
virtual int value(void)
{
printf("%s\n", __PRETTY_FUNCTION__);
return 30 + component->value();
}
};
int main()
{
CComponent *component = new CConcreteComponent();
printf("\n");
component = new CConcreteDecoratorA(component);
printf("\n");
component = new CConcreteDecoratorB(component);
printf("===============================================\n");
printf("%d\n", component->value());
printf("===============================================\n");
delete component;
}
執行結果
CComponent::CComponent()
CConcreteComponent::CConcreteComponent()
CComponent::CComponent()
CDecorator::CDecorator()
CConcreteDecoratorA::CConcreteDecoratorA(CComponent*)
CComponent::CComponent()
CDecorator::CDecorator()
CConcreteDecoratorB::CConcreteDecoratorB(CComponent*)
===============================================
virtual int CConcreteDecoratorB::value()
virtual int CConcreteDecoratorA::value()
virtual int CConcreteComponent::value()
60
===============================================
virtual CConcreteDecoratorB::~CConcreteDecoratorB()
virtual CConcreteDecoratorA::~CConcreteDecoratorA()
virtual CConcreteComponent::~CConcreteComponent()
virtual CComponent::~CComponent()
virtual CDecorator::~CDecorator()
virtual CComponent::~CComponent()
virtual CDecorator::~CDecorator()
virtual CComponent::~CComponent()
在此要思考裝飾者的結構式裡用 delete 是否恰當,原程式是在 Java 上時做,但 C++ 不具備有 garbage collection 的功能。若不再解構式中釋放則會產生 memory leak 的問題。但在另一個 case 裡則會引發錯誤。
使用時機須在思考
int main()
{
CComponent *component;
CConcreteComponent concreteComponent;
printf("\n");
component = new CConcreteDecoratorA(&concreteComponent);
printf("\n");
component = new CConcreteDecoratorB(component);
printf("===============================================\n");
printf("%d\n", component->value());
printf("===============================================\n");
delete component;
}
CComponent::CComponent()
CConcreteComponent::CConcreteComponent()
CComponent::CComponent()
CDecorator::CDecorator()
CConcreteDecoratorA::CConcreteDecoratorA(CComponent*)
CComponent::CComponent()
CDecorator::CDecorator()
CConcreteDecoratorB::CConcreteDecoratorB(CComponent*)
===============================================
virtual int CConcreteDecoratorB::value()
virtual int CConcreteDecoratorA::value()
virtual int CConcreteComponent::value()
60
===============================================
(執行 delete)
virtual CConcreteDecoratorB::~CConcreteDecoratorB()
virtual CConcreteDecoratorA::~CConcreteDecoratorA()
virtual CConcreteComponent::~CConcreteComponent()
virtual CComponent::~CComponent()
*** Error in `./decorator': double free or corruption (out): 0xbfa397c8 ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x767e2)[0xb74ee7e2]
/lib/i386-linux-gnu/libc.so.6(+0x77530)[0xb74ef530]
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZdlPv+0x1f)[0xb7691b4f]
./decorator[0x8048980]
./decorator[0x8048aec]
./decorator[0x8048b3f]
./decorator[0x8048c10]
./decorator[0x8048c63]
./decorator[0x80487f6]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf5)[0xb7491935]
./decorator[0x8048651]
======= Memory map: ========
08048000-0804a000 r-xp 00000000 08:01 393246 /home/archer/src/HeadFirstDesignPatterns/chap03/decorator
0804a000-0804b000 r--p 00001000 08:01 393246 /home/archer/src/HeadFirstDesignPatterns/chap03/decorator
0804b000-0804c000 rw-p 00002000 08:01 393246 /home/archer/src/HeadFirstDesignPatterns/chap03/decorator
0819b000-081bc000 rw-p 00000000 00:00 0 [heap]
b7433000-b7435000 rw-p 00000000 00:00 0
b7435000-b7476000 r-xp 00000000 08:01 656247 /lib/i386-linux-gnu/libm-2.17.so
b7476000-b7477000 r--p 00040000 08:01 656247 /lib/i386-linux-gnu/libm-2.17.so
b7477000-b7478000 rw-p 00041000 08:01 656247 /lib/i386-linux-gnu/libm-2.17.so
b7478000-b7625000 r-xp 00000000 08:01 656199 /lib/i386-linux-gnu/libc-2.17.so
b7625000-b7627000 r--p 001ad000 08:01 656199 /lib/i386-linux-gnu/libc-2.17.so
b7627000-b7628000 rw-p 001af000 08:01 656199 /lib/i386-linux-gnu/libc-2.17.so
b7628000-b762c000 rw-p 00000000 00:00 0
b762c000-b7647000 r-xp 00000000 08:01 656224 /lib/i386-linux-gnu/libgcc_s.so.1
b7647000-b7648000 r--p 0001a000 08:01 656224 /lib/i386-linux-gnu/libgcc_s.so.1
b7648000-b7649000 rw-p 0001b000 08:01 656224 /lib/i386-linux-gnu/libgcc_s.so.1
b7649000-b7725000 r-xp 00000000 08:01 1969970 /usr/lib/i386-linux-gnu/libstdc++.so.6.0.17
b7725000-b7726000 ---p 000dc000 08:01 1969970 /usr/lib/i386-linux-gnu/libstdc++.so.6.0.17
b7726000-b772a000 r--p 000dc000 08:01 1969970 /usr/lib/i386-linux-gnu/libstdc++.so.6.0.17
b772a000-b772b000 rw-p 000e0000 08:01 1969970 /usr/lib/i386-linux-gnu/libstdc++.so.6.0.17
b772b000-b7732000 rw-p 00000000 00:00 0
b7747000-b774b000 rw-p 00000000 00:00 0
b774b000-b774c000 r-xp 00000000 00:00 0 [vdso]
b774c000-b776c000 r-xp 00000000 08:01 656173 /lib/i386-linux-gnu/ld-2.17.so
b776c000-b776d000 r--p 0001f000 08:01 656173 /lib/i386-linux-gnu/ld-2.17.so
b776d000-b776e000 rw-p 00020000 08:01 656173 /lib/i386-linux-gnu/ld-2.17.so
bfa1a000-bfa3b000 rw-p 00000000 00:00 0 [stack]
Aborted (core dumped)
修改過適合 C++ 的作法
#include <string>
#include <iostream>
using namespace std;
class CComponent
{
public:
CComponent()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual ~CComponent()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual int value(void) = 0;
virtual string getInfo(void) = 0;
};
class CConcreteComponent : public CComponent
{
private:
int val;
public:
CConcreteComponent()
{
cout << __PRETTY_FUNCTION__ << endl;
val = 10;
}
virtual ~CConcreteComponent()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual int value(void)
{
return val;
}
virtual string getInfo(void)
{
return "CConcreteComponent";
}
};
class CDecorator : public CComponent
{
public:
CDecorator()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual ~CDecorator()
{
cout << __PRETTY_FUNCTION__ << endl;
}
// new mothod
virtual void newMethod(void) = 0;
};
class CConcreteDecoratorA : public CDecorator
{
private:
CComponent *m_component;
public:
CConcreteDecoratorA(CComponent *c) : m_component(c)
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual ~CConcreteDecoratorA()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual void newMethod(void)
{
}
// the same mothod but new behavior
virtual int value(void)
{
return 20 + m_component->value();
}
virtual string getInfo(void)
{
return m_component->getInfo() + " ,CConcreteDecoratorA";
}
};
修改過適合 C++ 的作法
#include <string>
#include <iostream>
using namespace std;
class CComponent
{
public:
CComponent()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual ~CComponent()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual int value(void) = 0;
virtual string getInfo(void) = 0;
};
class CConcreteComponent : public CComponent
{
private:
int val;
public:
CConcreteComponent()
{
cout << __PRETTY_FUNCTION__ << endl;
val = 10;
}
virtual ~CConcreteComponent()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual int value(void)
{
return val;
}
virtual string getInfo(void)
{
return "CConcreteComponent";
}
};
class CDecorator : public CComponent
{
public:
CDecorator()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual ~CDecorator()
{
cout << __PRETTY_FUNCTION__ << endl;
}
// new mothod
virtual void newMethod(void) = 0;
};
class CConcreteDecoratorA : public CDecorator
{
private:
CComponent *m_component;
public:
CConcreteDecoratorA(CComponent *c) : m_component(c)
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual ~CConcreteDecoratorA()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual void newMethod(void)
{
}
// the same mothod but new behavior
virtual int value(void)
{
return 20 + m_component->value();
}
virtual string getInfo(void)
{
return m_component->getInfo() + " ,CConcreteDecoratorA";
}
};
class CConcreteDecoratorB : public CDecorator
{
private:
CComponent *m_component;
public:
CConcreteDecoratorB(CComponent *c) : m_component(c)
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual ~CConcreteDecoratorB()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual void newMethod(void)
{
}
// the same mothod but new behavior
virtual int value(void)
{
return 30 + m_component->value();
}
virtual string getInfo(void)
{
return m_component->getInfo() + " ,CConcreteDecoratorA";
}
};
int main()
{
CConcreteComponent m;
cout << endl;
CConcreteDecoratorA a(&m);
cout << endl;
CConcreteDecoratorB b(&a);
cout << "=============================================" << endl;
cout << "Info : " << m.getInfo() << endl;
cout << "Value: " <<m.value() << endl;
cout << "=============================================" << endl;
cout << "Info : " << a.getInfo() << endl;
cout << "Value: " << a.value() << endl;
cout << "=============================================" << endl;
cout << "Info : " << b.getInfo() << endl;
cout << "Value: " << b.value() << endl;
cout << "=============================================" << endl;
}
修正了動態配置所產生的 memory leak 的問題,但在使用上似乎不能向上例如此彈性。
用 shared_ptr 解決動態配置問題 (only supported by c++11)
#include <string>
#include <iostream>
#include <memory>
using namespace std;
class CComponent
{
public:
CComponent()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual ~CComponent()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual int value(void) = 0;
virtual string getInfo(void) = 0;
};
class CConcreteComponent : public CComponent
{
private:
int val;
public:
CConcreteComponent()
{
cout << __PRETTY_FUNCTION__ << endl;
val = 10;
}
virtual ~CConcreteComponent()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual int value(void)
{
return val;
}
virtual string getInfo(void)
{
return "CConcreteComponent";
}
};
class CDecorator : public CComponent
{
public:
CDecorator()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual ~CDecorator()
{
cout << __PRETTY_FUNCTION__ << endl;
}
// new mothod
virtual void newMethod(void) = 0;
};
class CConcreteDecoratorA : public CDecorator
{
private:
shared_ptr<CComponent> m_component;
public:
CConcreteDecoratorA(shared_ptr<CComponent> c) : m_component(c)
{
cout << __PRETTY_FUNCTION__ << endl;
cout << "use count:" << c.use_count() << endl;
}
virtual ~CConcreteDecoratorA()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual void newMethod(void)
{
}
// the same mothod but new behavior
virtual int value(void)
{
return 20 + m_component->value();
}
virtual string getInfo(void)
{
return m_component->getInfo() + " ,CConcreteDecoratorA";
}
};
class CConcreteDecoratorB : public CDecorator
{
private:
shared_ptr<CComponent> m_component;
public:
CConcreteDecoratorB(shared_ptr<CComponent> c) : m_component(c)
{
cout << __PRETTY_FUNCTION__ << endl;
cout << "use count:" << c.use_count() << endl;
}
virtual ~CConcreteDecoratorB()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual void newMethod(void)
{
}
// the same mothod but new behavior
virtual int value(void)
{
return 30 + m_component->value();
}
virtual string getInfo(void)
{
return m_component->getInfo() + " ,CConcreteDecoratorA";
}
};
int main()
{
shared_ptr<CComponent> m(new CConcreteComponent());
cout << "m's use count:" << m.use_count() << endl;
cout << endl;
shared_ptr<CComponent> a(new CConcreteDecoratorA(m));
cout << "a's use count:" << a.use_count() << endl;
cout << endl;
shared_ptr<CComponent> b(new CConcreteDecoratorB(m));
cout << "b's use count:" << b.use_count() << endl;
cout << "=============================================" << endl;
cout << "Info : " << m->getInfo() << endl;
cout << "Value: " << m->value() << endl;
cout << "=============================================" << endl;
cout << "Info : " << a->getInfo() << endl;
cout << "Value: " << a->value() << endl;
cout << "=============================================" << endl;
cout << "Info : " << b->getInfo() << endl;
cout << "Value: " << b->value() << endl;
cout << "=============================================" << endl;
}
2013年9月15日 星期日
XBMC used strategy pattern to implement player to playback file.
XBMC 使用 Strategy pattern 實作 player,各 player 實作 IPlayer 介面,提供控制方法由 CApplication 控制
在執行時期由 CPlayerCoreFactory::Get().CreatePlayer(eNewCore, *this)
動態決定要掛載的 player 實體
在執行時期由 CPlayerCoreFactory::Get().CreatePlayer(eNewCore, *this)
動態決定要掛載的 player 實體
bool CApplication::PlayFile(const CFileItem& item, bool bRestart) {
:
:
:if (!m_pPlayer) { m_eCurrentPlayer = eNewCore; m_pPlayer = CPlayerCoreFactory::Get().CreatePlayer(eNewCore, *this); }
:
}
訂閱:
文章 (Atom)