记录学习过程中的点点滴滴
2011年三月
Pthreads并行编程之spin lock与mutex性能对比分析[zz]
三 29th
原文地址:http://www.parallellabs.com/2010/01/31/pthreads-programming-spin-lock-vs-mutex-performance-analysis/
Pthreads提供的Mutex锁操作相关的API主要有:
pthread_mutex_lock (pthread_mutex_t *mutex);
pthread_mutex_trylock (pthread_mutex_t *mutex);
pthread_mutex_unlock (pthread_mutex_t *mutex);
Pthreads提供的与Spin Lock锁操作相关的API主要有:
pthread_spin_lock (pthread_spinlock_t *lock);
pthread_spin_trylock (pthread_spinlock_t *lock);
pthread_spin_unlock (pthread_spinlock_t *lock);
从实现原理上来讲,Mutex属于sleep-waiting类型的锁。例如在一个双核的机器上有两个线程(线程A和线程B),它们分别运行在 Core0和Core1上。假设线程A想要通过pthread_mutex_lock操作去得到一个临界区的锁,而此时这个锁正被线程B所持有,那么线程 A就会被阻塞(blocking),Core0 会在此时进行上下文切换(Context Switch)将线程A置于等待队列中,此时Core0就可以运行其他的任务(例如另一个线程C)而不必进行忙等待。而Spin lock则不然,它属于busy-waiting类型的锁,如果线程A是使用pthread_spin_lock操作去请求锁,那么线程A就会一直在 Core0上进行忙等待并不停的进行锁请求,直到得到这个锁为止。
详细信息请点击:这里
linux下跨线程的越界访问hook方法
三 29th
我们知道在linux下多线程之间,是共用同一片存储区域的,可以访问共享的全局变量等,但是能否访问线程内部的局部变量呢,会不会出现越界异常呢?今天笔者尝试了一下,发现可以在线程间越界访问!
代码如下:
/* * Author:yaronli <jidalyg_8711@163.com> * http://www.yaronspace.cn/blog * * File: hookpthread.c * Create Date: 2011-03-27 21:22:31 * */ #include <stdio.h> #include <pthread.h> void * fun(void * i) { int a=20; printf("fun: &a:[%x]-----a:[%d]\n", &a,a); sleep(3); printf("fun: &a:[%x]-----a:[%d]\n", &a,a); pthread_exit(NULL); } void * hook(void * a) { int b=10; sleep(1); printf("hook: &b:[%x]\n", &b); printf("hook: &a:[%d]\n", *(&b-10489856/4)); *(&b-10489856/4)=30; pthread_exit(NULL); } int main() { pthread_t pidfun,pidhook; pthread_create(&pidfun, NULL, fun, NULL); pthread_create(&pidhook, NULL, hook, NULL); sleep(5); return 0; } /* vim: set ts=4 sw=4: */
该程序首先是在启动两个线程,在fun线程中设置局部变量a=20并显示出来,在hook线程中尝试读取a的变量值并试图更改它,然后再次显示变量a的值
在我的机器上的输出如下:
fun: &a:[419c512c]-----a:[20] hook: &b:[423c612c] hook: &a:[20] fun: &a:[419c512c]-----a:[30]
可以发现a的在值在线程hook中被修改成功了,并没有出现越界访问异常
TIPS:
1. 10489856/4 关于这个值的获取是通过&b和&a的地址相减得到的,至于为什么除4,是因为&b是int型的指针,而指针的加减法的单位是4个字节,所以需要除以4,这里我也是调试好半边才搞明白的.
drupal号称比wordpress更强大
三 28th
drupal没有wordpress普及,但是功能应该比wordpress更强大,有以下8个用途:
项目主页:http://drupal.org
1. 文件存储分享站点
使用Drupal创建文件分享,你可以使用 CCK 和 Views ,也包括一些模块,比如Media Mover, Filebrowser 或者 Web File Manager。看看Box.net,你会非常感兴趣的^_^。
2. 社交网站
在社交网络能力方面,Drupal可能是最好的CMS。Drupal提供了强大的用户管理和权限管理系统。但是如果你想创建强大的社交网站,就需要一些模块,见http://drupal.org/node/206724。
你想看一些案例?Imbee 或者 GoingOn。
3. Twitter Clone
建议你不要尝试利用Drupal创建Twitter竞争产品,但是,如果你想整合Twitter功能到你的站点,Drupal的微博模块 可以帮到你。
4. 新闻News portal
如果你想创建新闻站点或杂志站点,Drupal的完美的选择。使用CCK 和 Views ,你可以创建所有的发布内容类型,并且可灵活列表。这样的新闻站点非常之多,比如New York Observer。
5. 博客网络
用Drupal创建博客网站,很轻松,甚至无需额外模块。看看 Wisebread吧。
6. 视频分享站点
这类站点太耗带宽了,如果你决定创建,那么Drupal来帮你实现吧。FlashVideo 模块提供了创建Youtube克隆的强大能力,它整合了CCK,转换视频到FLV,并有分享代码。另外你也可以尝试Media Mover 和 SWF Tools 。MTV UK 站点就是Drupal创建的。
7. 图片分享站点
Image module ,这个模块将派上用场,可让你创建类Flickr站点,很好很强大。MyFinePix 就是Drupal创建的照片分享站点。
8. 类Digg-like news site
感谢 Drigg module, 这个模块可帮助你快速建立Digg克隆站点。流行的设计社交新闻网Designbump在使用Drupal。
linux查看系统的启动时间和运行时间
三 17th
1. uptime命令
输出:09:32:17 up 8:41, 1 user, load average: 0.01, 0.00, 0.00
其中8:41代表系统已经运行8小时41分
2.查看/proc/uptime
[yangguang@sim124 ~]$ cat /proc/uptime 31351.83 31341.94 #第一个数字代表已经运行的时间 #可以用date命令来计算出系统的启动时间 [yangguang@sim124 ~]$ date -d "$(awk -F. '{print $1}' /proc/uptime) second ago" +"%Y-%m-%d %H:%M:%S" 2011-03-17 00:50:51 #使用date命令计算系统的运行时间 [yangguang@sim124 ~]$ cat /proc/uptime| awk -F. '{run_days=$1 / 86400;run_hour=($1 % 86400)/3600;run_minute=($1 % 3600)/60;run_second=$1 % 60;printf("系统已运行:%d天%d时%d分%d秒\n",run_days,run_hour,run_minute,run_second)}' 系统已运行:0天8时45分27秒
字符串的哈希算法hnv的介绍和实现
三 16th
fnv全称”Fowler/Noll/Vo”,特点是快速而且冲突率比较低,在url hostname或者ip的哈希有广泛的应用, 详细信息请点击这里
下面是fnv在Sheepdog中用法的实现,将任意字符串转化为uint64_t
/* * 64 bit FNV-1a non-zero initial basis */ #define FNV1A_64_INIT ((uint64_t) 0xcbf29ce484222325ULL) /* * 64 bit Fowler/Noll/Vo FNV-1a hash code */ static inline uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval) { unsigned char *bp = (unsigned char *) buf; unsigned char *be = bp + len; while (bp < be) { hval ^= (uint64_t) *bp++; hval += (hval << 1) + (hval << 4) + (hval << 5) + (hval << 7) + (hval << 8) + (hval << 40); } return hval; }

sheepdog源码分析之关键模块介绍(一)
三 15th
1) Worker工作线程模块
该模块是作为sheepdog工作线程模块,存在多个工作线程,默认NR_WORKER_THREAD =64个工作线程;线程的入口函数为worker_routine,同时struct work_queue中pending_list是双向链表,worker_routine从该链表中读取任务,然后执行,接着将执行过的任务放到struct worker_info中finished_list双向链表,然后向main thread发送一个信号,接着调用bs_thread_request_done来执行finished_list中任务的done函数,该函数的作用是发送响应信息。涉及的文件主要是worker.c和Worker.h
struct work_queue {
int wq_state; // int nr_active; //当前活跃的任务数目 struct list_head pending_list;//待执行的任务列表 struct list_head blocked_list; //没有用处了 }; struct worker_info { struct list_head worker_info_siblings;//链表的连接器,目前只有一个worker_info int nr_threads; //线程个数 pthread_mutex_t finished_lock; // struct list_head finished_list; /* wokers sleep on this and signaled by tgtd */ pthread_cond_t pending_cond; /* locked by tgtd and workers */ pthread_mutex_t pending_lock; /* protected by pending_lock */ struct work_queue q; pthread_mutex_t startup_lock; pthread_t worker_thread[0]; //工作线程的数据结构 }; |
这里需要特殊说明的是,有关任务Worker的属性WORK_SIMPLE和WORK_ORDERED,及有关block相关的函数,在0.2版本中应该是没有用处的,当时我也迷惑一阵。
Sheepdog存在三类的工作任务:
- Request: 所有来自客户端或者其他sheep的请求
- Recovery_work: 数据恢复任务
- Delete_work: 删除vdi的任务
- Cpg_event_work: 该任务作为cpg有关集群管理的任务,例如节点加入和send_message消息发送等,sheep保证当前系统只运行一个cpg_event_work任务,从sys->cpg_event_siblings中是未执行的任务。
sheepdog源码分析之关键数据结构介绍
三 15th
关键数据结构的说明
1.
struct sd_req {
uint8_t proto_ver; uint8_t opcode; //操作类型 uint16_t flags;// uint32_t epoch; uint32_t id; uint32_t data_length; uint32_t opcode_specific[8]; }; |
struct sd_rsp {
uint8_t proto_ver; uint8_t opcode; uint16_t flags; uint32_t epoch; uint32_t id; uint32_t data_length; uint32_t result; uint32_t opcode_specific[7]; }; |
这两个数据结构应该是作为抽象类,可以看出sizeof(struct sd_req) == sizeof(struct sd_rsp),这个是设计者故意为之,因为在发送请求和接收响应时,客户端是使用同一片内存区域; |
2.
struct sd_obj_req {
uint8_t proto_ver; uint8_t opcode; uint16_t flags; uint32_t epoch; uint32_t id; uint32_t data_length; uint64_t oid;//object id uint64_t cow_oid; uint32_t copies;//副本个数 uint32_t tgt_epoch; uint64_t offset; }; |
struct sd_obj_rsp {
uint8_t proto_ver; uint8_t opcode; uint16_t flags; uint32_t epoch; uint32_t id; uint32_t data_length; uint32_t result; uint32_t copies; uint32_t pad[6]; }; |
对object进行请求及响应,这里需要说明的一点:object在Sheepdog中作为数据存储单元,分为data_object 和vdi_object,分别存储数据和vdi的元数据,即后面提到的sheepdog_inode的内容,分片大小为4M。不知作者为何分这么小的分片? |
struct sd_vdi_req { uint8_t proto_ver; uint8_t opcode; uint16_t flags; uint32_t epoch; uint32_t id; uint32_t data_length; uint64_t vdi_size; //vdi的大小 uint32_t base_vdi_id; uint32_t copies; uint32_t snapid; uint32_t pad[3]; }; |
struct sd_vdi_rsp { uint8_t proto_ver; uint8_t opcode; uint16_t flags; uint32_t epoch; uint32_t id; uint32_t data_length; uint32_t result; uint32_t rsvd; uint32_t vdi_id; uint32_t pad[5]; }; |
对vdi进行有关操作的请求和响应 |
C语言中宏定义的##连接符和#转换符的用法介绍
三 11th
1. ##连接符的用法
在C语言中,## 连接符号由两个井号组成,其功能是在带参数的宏定义中将两个子串(token)联接起来,从而形成一个新的子串,一般跟在宏定义参数的前面。
2.#转换符的用法
#转化符是将传递的参数作为字符串来进行处理。
例如定义如下宏:
#define pasrse( i ) printf( "token" #i " = %d", token##i ) //同时定义如下的变量 int token1 = 1;
则调用parse(1)的打印结果为:
#宏展开: printf("token" "1" "= %d", token1); token1=1
3.宏定义的可变参数
在宏定义中使用可变参数,只需在参数后面加入”…”,然后使用##连接即可
例如下面的例子:
#define LOG_INFO(fmt, args...) \ do { \ log_write("LOG_INFO", __func__, __FILE__, __LINE__, fmt, ##args); \ }while(0) //其中log_write的原型为: void log_write(const char *level, const char *func, const char *file, int line, const char *fmt, ...);
sheepdog源码学习二之代码目录结构介绍
三 9th
目录结构
include/
- config.h: 定义公共的宏
- bitops.h: 有关的位操作,主要是针对oid的使用情况
- util.h: 公用操作的实现
- list.h: 双向链表的实现,主要是参考linux内核代码的实现
- event.h: epoll异步事件模型
- logger.h: 日志操作
- net.h: socket网络IO
- sheepdog_proto.h: sheepdog中用到的操作类型及数据结构的定义:
- sheep.h: Sheep本身需要的数据结构和操作类型,与sheedog_proto.h为何分开定义暂不清楚
lib/
- logger.c: 有关日志文件的操作的实现
- net.c: 有关socket网络IO的实现
- event.c: 事件模型的有关实现
sheep/
- sheep_priv.h: 定义相关数据结构和声明相关函数
- work.h: 定义工作队列对外提供的数据结构和API
- work.c: 实现工作线程
- sdnet.c: 对网络IO的进一步封装,包括回调函数的定义
- group.c: 利用corosync对组进行管理
- store.c: sheepdog有关数据存储、epoch和日志的操作
- vdi.c: sheepdog中vdi的相关操作
- sheep.c: sheep的main函数入口
collie/
- treeview.h: vdi tree的有关操作
- treeview.c: vdi tree的实现
- collie.c: 对sheep进行管理实现
Vim纵向编辑模式的用法
三 7th
启动方法
在 Vim 命令模式下,移动游标定位于某一个位置,键入 ctrl-v
后状态栏上出现 VISUAL BLOCK 字样,即进入纵向编辑模式。移动游标以按需选择待编辑的区域
我们将下面的例子来说明三种用法,序列
10.60.1.191 10.60.1.192 10.60.1.193
修改为序列:
ping -c 4 10.60.5.191 >> resultso ping -c 4 10.60.5.192 >> resultso ping -c 4 10.60.5.193 >> resultso
用法
1. 修改选中的列:将ip字段中的1修改为5
1>crtl – v 进入列编辑模式
2> G 移动光标至最后一行,选中所要编辑的列
3> r 进入修改模式
4> 输入数字5,并按esc退出输入模式
结果如下:
10.60.5.191 10.60.5.192 10.60.5.193
2. 前向添加: 添加字符串ping -c 4
1>crtl – v 进入列编辑模式
2> G 移动光标至最后一行,可视块覆盖了第一列
3> I 进入行首插入模式
4> ping -c 4,并按esc退出输入模式
结果如下:
ping -c 4 10.60.5.191 ping -c 4 10.60.5.192 ping -c 4 10.60.5.193
3. 后添加模式:尾部追加 >> result
1>crtl – v 进入列编辑模式
2>G 移动光标至最后一行,可视块覆盖了最后一列
3> A 进入行尾插入模式
4> <<result,并按esc退出输入模式
搞定….
参考资料:http://www.ibm.com/developerworks/cn/linux/l-cn-vimcolumn/index.html?ca=drs-
近期评论