class CourseSign < ActiveRecord::Base
attr_accessible :course_id, :user_id, :streak
belongs_to :user
belongs_to :course
validates :user, :presence => true
validates :course, :presence => true
validates :user_id, :uniqueness => {:scope => :course_id}
scope :current_signs, lambda {|course,date|{:conditions =>
['course_id=? AND DATE(created_at)=?', course.id, Date.today]
}}
scope :current_signs_for_user, lambda {|course,date,user|
current_signs(course,date).where(:user_id => user.id)
}
end
module CourseSignModule
# 2 课程模型上需要封装用户进行签到的方法
def sign(user)
return if !current_sign_for_user(user,Date.today).blank?
CourseSign.create(:course_id => self.id, :user_id => user.id, :streak => current_streak_for(user) )
end
# 截至今天的连续签到天数
def current_streak_for(user)
@yesterday = current_sign_for_user(user,Date.today-1)
return 1 if @yesterday.blank?
@yesterday.streak + 1
end
def current_sign_for_user(user,date)
CourseSign.current_signs_for_user(self,date,user).first
end
# 3 课程模型上需要封装获取总签到数的查询方法
def signs_count
CourseSign.where(:course_id => self.id).count
end
# 4 课程模型上需要封装某个用户今天是第几个签到的查询方法
def sign_number(user)
@course_sign = current_sign_for_user(user, Date.today)
index = current_signs.index(@course_sign)
index && index + 1
end
def current_signs
CourseSign.current_signs(self,Date.today).order('id asc')
end
# 6 课程模型上需要封装获取当天签到人数的查询方法
def current_signs_count
current_signs.size
end
end
require "spec_helper"
describe Course do
context '签到模块' do
before do
@user = FactoryGirl.create(:user)
@course = FactoryGirl.create(:course)
end
describe '#sign' do
it{expect {@course.sign(@user)}.to change {CourseSign.count}.by(1)}
end
describe '#current_streak_for' do
context '昨天没有签到' do
it {@course.current_streak_for(@user) == 1}
end
context '昨天前天连续签到了' do
before do
Timecop.travel(Date.today - 2)
@course.sign(@user)
Timecop.travel(Date.today - 1)
@course.sign(@user)
end
it {@course.current_streak_for(@user) == 3}
end
end
describe '#signs_count' do
let(:user1) {FactoryGirl.create :user}
let(:user2) {FactoryGirl.create :user}
let(:user3) {FactoryGirl.create :user}
let(:course2) {FactoryGirl.create :course}
before do
course2.sign(user1)
@course.sign(user1)
@course.sign(user2)
@course.sign(user3)
end
it{ @course.signs_count == 3 }
it{ course2.signs_count == 1 }
end
describe '#sign_number' do
let(:user1) {FactoryGirl.create :user}
let(:user2) {FactoryGirl.create :user}
before do
@course.sign(user1)
@course.sign(user2)
end
it{ @course.sign_number(user2) == 2}
end
describe '#current_signs_count' do
let(:user1) {FactoryGirl.create :user}
let(:user2) {FactoryGirl.create :user}
let(:user3) {FactoryGirl.create :user}
let(:course2) {FactoryGirl.create :course}
before do
course2.sign(user1)
@course.sign(user1)
@course.sign(user2)
@course.sign(user3)
end
it {@course.current_signs_count.should == 3}
end
end
end
1.Linux“线程”
进程与线程之间是有区别的,不过Linux内核只提供了轻量进程的支持,未实现线程模型。Linux是一种“多进程单线程”的操作系统。Linux 本身只有进程的概念,而其所谓的“线程”本质上在内核里仍然是进程。
大 家知道,进程是资源分配的单位,同一进程中的多个线程共享该进程的资源(如作为共享内存的全局变量)。Linux中所谓的“线程”只是在被创建时 clone了父进程的资源,因此clone出来的进程表现为“线程”,这一点一定要弄清楚。因此,Linux“线程”这个概念只有在打冒号的情况下才是最 准确的。
目前Linux中最流行的线程机制为LinuxThreads,所采用的就是线程-进程“一对一”模型,调度交给核心,而在用户级实现一个包括信号 处理在内的线程管理机制。LinuxThreads由Xavier Leroy (Xavier.Leroy@inria.fr)负责开发完成,并已绑 定在GLIBC中发行,它实现了一种BiCapitalized面向Linux的Posix 1003.1c “pthread”标准接口。Linuxthread可以支持Intel、Alpha、MIPS等平台上的多处理器系统。
按照POSIX 1003.1c 标准编写的程序与Linuxthread 库相链接即可支持Linux平台上的多线程,在程序中需包含头文件pthread. h,在编译链接时使用命令:
gcc -D -REENTRANT -lpthread xxx. c
其中-REENTRANT宏使得相关库函数(如stdio.h、errno.h中函数) 是可重入的、线程安全的(thread-safe),-lpthread则意味着链接库目录下的libpthread.a或libpthread.so文 件。使用Linuxthread库需要2.0以上版本的Linux内核及相应版本的C库(libc 5.2.18、libc 5.4.12、libc 6)。
2.“线程”控制
线程创建
进程被创建时,系统会为其创建一个主线程,而要在进程中创建新的线程,则可以调用pthread_create:
pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *
(start_routine)(void*), void *arg);
start_routine为新线程的入口函数,arg为传递给start_routine的参数。
每个线程都有自己的线程ID,以便在进程内区分。线程ID在pthread_create调用时回返给创建线程的调用者;一个线程也可以在创建 后使用pthread_self()调用获取自己的线程ID:
pthread_self (void) ;
线程退出
线程的退出方式有三:
(1)执行完成后隐式退出;
(2)由线程本身显示调用pthread_exit 函数退出;
pthread_exit (void * retval) ;
(3)被其他线程用pthread_cance函数终止:
pthread_cance (pthread_t thread) ;
在某线程中调用此函数,可以终止由参数thread 指定的线程。
如果一个线程要等待另一个线程的终止,可以使用pthread_join函数,该函数的作用是调用pthread_join的线程将被挂起直到 线程ID为参数thread的线程终止:
pthread_join (pthread_t thread, void** threadreturn);
3.线程通信
线程互斥
互斥意味着“排它”,即两个线程不能同时进入被互斥保护的代码。Linux下可以通过pthread_mutex_t 定义互斥体机制完成多线程的互斥操作,该机制的作用是对某个需要互斥的部分,在进入时先得到互斥体,如果没有得到互斥体,表明互斥部分被其它线程拥有,此 时欲获取互斥体的线程阻塞,直到拥有该互斥体的线程完成互斥部分的操作为止。
下面的代码实现了对共享全局变量x 用互斥体mutex 进行保护的目的:
int x; // 进程中的全局变量
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL); //按缺省的属性初始化互斥体变量mutex
pthread_mutex_lock(&mutex); // 给互斥体变量加锁
… //对变量x 的操作
phtread_mutex_unlock(&mutex); // 给互斥体变量解除锁
线程同步
同步就是线程等待某个事件的发生。只有当等待的事件发生线程才继续执行,否则线程挂起并放弃处理器。当多个线程协作时,相互作用的任务必须在一 定的条件下同步。
Linux下的C语言编程有多种线程同步机制,最典型的是条件变量(condition variable)。pthread_cond_init用来创建一个条件变量,其函数原型为:
pthread_cond_init (pthread_cond_t *cond, const pthread_condattr_t *attr);
pthread_cond_wait和pthread_cond_timedwait用来等待条件变量被设置,值得注意的是这两个等待调用需要 一个已经上锁的互斥体mutex,这是为了防止在真正进入等待状态之前别的线程有可能设置该条件变量而产生竞争。pthread_cond_wait的函 数原型为:
pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex);
pthread_cond_broadcast用于设置条件变量,即使得事件发生,这样等待该事件的线程将不再阻塞:
pthread_cond_broadcast (pthread_cond_t *cond) ;
一.什么是SSI
SSI:Server Side Include,是一种基于服务端的网页制作技术,大多数(尤其是基于Unix平台)的web服务器如Netscape Enterprise Server等均支持SSI命令。
它的工作原因是:在页面内容发送到客户端之前,使用SSI指令将文本、图片或代码信息包含到网页中。对于在多个文件中重复出现内容,使用SSI是一种简便的方法,将内容存入一个包含文件中即可,不必将其输入所有文件。通过一个非常简单的语句即可调用包含文件,此语句指示 Web 服务器将内容插入适当网页。而且,使用包含文件时,对内容的所有更改只需在一个地方就能完成。二.如何在nginx上配置SSI
需要的选项主要是以下三个:
ssi: 默认值off,启用ssi时将其设为on
ssi_silent_errors: 默认值off,开启后在处理SSI文件出错时不输出错误提示"[an error occurred while processing the directive]"。
ssi_types: 默认是text/html,所以如果需支持html,则不需要设置这句,如果需要支持shtml则需要设置:ssi_types text/shtml
三个参数可以放在http, server或location作用域下。三. 实例
server { listen 10.3.9.27:80; server_name www.ball.com; location / { ssi on; ssi_silent_errors on; ssi_types text/shtml; index index.shtml; root /usr/local/web/wwwroot; expires 30d; access_log /data/logs/www.ball.com-access_log main; } }
了解更多SSI配置及命令请猛击这里!