1 互斥锁

在线程实际运行过程中,我们经常需要多个线程保持同步。

这时可以用互斥锁来完成任务。互斥锁的使用过程中,主要有

pthread_mutex_init

pthread_mutex_destory

pthread_mutex_lock

pthread_mutex_unlock

这几个函数以完成锁的初始化,锁的销毁,上锁和释放锁操作。

1.1 锁的创建

锁可以被动态或静态创建,可以用宏PTHREAD_MUTEX_INITIALIZER来静态的初始化锁,采用这种方式比较容易理解,互斥锁是pthread_mutex_t的结构体,而这个宏是一个结构常量,如下可以完成静态的初始化锁:

pthread_mutex_t mutex =PTHREAD_MUTEX_INITIALIZER;

另外锁可以用pthread_mutex_init函数动态的创建,函数原型如下:

int pthread_mutex_init(pthread_mutex_t*mutex, const pthread_mutexattr_t * attr)

1.2 锁的属性

互斥锁属性可以由pthread_mutexattr_init(pthread_mutexattr_t *mattr)来初始化,然后可以调用其他的属性设置方法来设置其属性。

互斥锁的范围:可以指定是该进程与其他进程的同步还是同一进程内不同的线程之间的同步。可以设置为PTHREAD_PROCESS_SHARE和PTHREAD_PROCESS_PRIVATE。默认是后者,表示进程内使用锁。可以使用

int pthread_mutexattr_setpshared(pthread_mutexattr_t*mattr, int pshared)

pthread_mutexattr_getpshared(pthread_mutexattr_t*mattr,int *pshared)

用来设置与获取锁的范围;

互斥锁的类型:有以下几个取值空间:

PTHREAD_MUTEX_TIMED_NP,这是缺省值,也就是普通锁。当一个线程加锁以后,其余请求锁的线程将形成一个等待队列,并在解锁后按优先级获得锁。这种锁策略保证了资源分配的公平性。
PTHREAD_MUTEX_RECURSIVE_NP,嵌套锁,允许同一个线程对同一个锁成功获得多次,并通过多次unlock解锁。如果是不同线程请求,则在加锁线程解锁时重新竞争。
PTHREAD_MUTEX_ERRORCHECK_NP,检错锁,如果同一个线程请求同一个锁,则返回EDEADLK,否则与PTHREAD_MUTEX_TIMED_NP类型动作相同。这样就保证当不允许多次加锁时不会出现最简单情况下的死锁。
PTHREAD_MUTEX_ADAPTIVE_NP,适应锁,动作最简单的锁类型,仅等待解锁后重新竞争。

可以用
pthread_mutexattr_settype(pthread_mutexattr_t *attr , int type)
pthread_mutexattr_gettype(pthread_mutexattr_t *attr , int *type)

获取或设置锁的类型。

1.3 锁的释放

调用pthread_mutex_destory之后,可以释放锁占用的资源,但这有一个前提上锁当前是没有被锁的状态。

1.4 锁操作

对锁的操作主要包括加锁 pthread_mutex_lock()、解锁pthread_mutex_unlock()和测试加锁pthread_mutex_trylock()三个。

int pthread_mutex_lock(pthread_mutex_t*mutex)
int pthread_mutex_unlock(pthread_mutex_t *mutex)
int pthread_mutex_trylock(pthread_mutex_t *mutex)

pthread_mutex_trylock()语义与pthread_mutex_lock()类似,不同的是在锁已经被占据时返回EBUSY而不是挂起等待。

1.5 代码讲解:

代码说明1:互斥锁基本应用

#include <stdio.h>
#include <pthread.h>
#include <unistd.h> pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int count = 0; void* consume(void *arg)
{
while(1)
{
pthread_mutex_lock(&mutex);
printf("************************consume begin lock\n");
printf("************************consumed %d\n",count);
count++;
sleep(2);
printf("************************consume over lock\n");
pthread_mutex_unlock(&mutex);
printf("************************I'm out of pthread_mutex\n");
sleep(1);
} return NULL;
} void* produce( void * arg )
{
while(1)
{
pthread_mutex_lock(&mutex );
printf("product begin lock\n");
printf("produced %d\n", count);
printf("product over lock\n");
pthread_mutex_unlock(&mutex );
printf("I'm out of pthread_mutex\n");
sleep(1);
} return NULL;
} int main( void )
{
pthread_t thread1,thread2;
pthread_create(&thread1, NULL, &produce, NULL );
pthread_create(&thread2, NULL, &consume, NULL );
pthread_join(thread1,NULL);
pthread_join(thread2,NULL);
return 0;
}

结果说明:

[root@rocket lock-free]# g++ -g -o pthread_mutex_lockpthread_mutex_lock.cpp -lpthread

[root@rocket lock-free]#./pthread_mutex_lock

product begin lock

produced 0

product over lock

I'm out of pthread_mutex

************************consume beginlock

************************consumed 0

/*中间等待了2秒但是product线程没有执行!*/

************************consume overlock

************************I'm out ofpthread_mutex

product begin lock

produced 1

product over lock

I'm out of pthread_mutex

product begin lock

produced 1

product over lock

I'm out of pthread_mutex

************************consume beginlock

************************consumed 1

************************consume overlock

************************I'm out ofpthread_mutex

product begin lock

produced 2

product over lock

I'm out of pthread_mutex

************************consume beginlock

************************consumed 2

************************consume overlock

************************I'm out ofpthread_mutex

代码说明2:pthread_mutext_trylock使用

#include <stdio.h>
#include <pthread.h>
#include <unistd.h> pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int count = 0; void* consume(void *arg)
{
while(1)
{
pthread_mutex_lock(&mutex);
printf("************************consume begin lock\n");
printf("************************consumed %d\n",count);
count++;
sleep(2);
printf("************************consume over lock\n");
pthread_mutex_unlock(&mutex);
printf("************************I'm out of pthread_mutex\n");
sleep(1);
} return NULL;
} void* produce( void * arg )
{
while(1)
{
if(pthread_mutex_trylock(&mutex ) == 0)
{
printf("product begin lock\n");
printf("produced %d\n", count );
printf("product over lock\n");
pthread_mutex_unlock(&mutex);
printf("I'm out of pthread_mutex\n");
sleep(1);
}
else
{
printf("I have try!But i can`t lock the mutex!\n");
sleep(1);
}
} return NULL;
} int main( void )
{
pthread_t thread1,thread2;
pthread_create(&thread1, NULL, &produce, NULL );
pthread_create(&thread2, NULL, &consume, NULL );
pthread_join(thread1,NULL);
pthread_join(thread2,NULL);
return 0;
}

结果说明:

[root@rocket lock-free]# g++ -g -o pthread_mutex_trylock pthread_mutex_trylock.cpp -lpthread

[root@rocket lock-free]#./pthread_mutex_trylock

************************consume beginlock

************************consumed 0

/* trylock没有成功马上返回! */

I have try!But i can`t lock the mutex!

I have try!But i can`t lock the mutex!

************************consume overlock

************************I'm out ofpthread_mutex

product begin lock

produced 1

product over lock

I'm out of pthread_mutex

************************consume beginlock

************************consumed 1

I have try!But i can`t lock the mutex!

I have try!But i can`t lock the mutex!

************************consume overlock

************************I'm out ofpthread_mutex

product begin lock

produced 2

product over lock

I'm out of pthread_mutex

************************consume beginlock

************************consumed 2

I have try!But i can`t lock the mutex!

I have try!But i can`t lock the mutex!

************************consume overlock

************************I'm out ofpthread_mutex

2 读写锁

读写锁是因为有3种状态,所以可以有更高的并行性。

2.1 特性

一次只有一个线程可以占有写模式的读写锁, 但是可以有多个线程同时占有读模式的读写锁,正是因为这个特性,当读写锁是写加锁状态时,在这个锁被解锁之前, 所有试图对这个锁加锁的线程都会被阻塞。

当读写锁在读加锁状态时, 所有试图以读模式对它进行加锁的线程都可以得到访问权, 但是如果线程希望以写模式对此锁进行加锁, 它必须阻塞直到所有的线程释放锁。

通常,当读写锁处于读模式锁住状态时,如果有另外线程试图以写模式加锁,读写锁通常会阻塞随后的读模式锁请求, 这样可以避免读模式锁长期占用, 而等待的写模式锁请求长期阻塞。

2.2 适用性

读写锁适合于对数据结构的读次数比写次数多得多的情况。因为,读模式锁定时可以共享, 以写模式锁住时意味着独占, 所以读写锁又叫共享-独占锁。

2.3 API初始化和销毁

#include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
成功则返回0,出错则返回错误编号

同互斥锁一样,在释放读写锁占用的内存之前,需要先通过pthread_rwlock_destroy对读写锁进行清理工作, 释放由init分配的资源。

2.4 读和写

#include <pthread.h>
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

这3个函数分别实现获取读锁, 获取写锁和释放锁的操作. 获取锁的两个函数是阻塞操作

同样,非阻塞的函数为:

#include <pthread.h>
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

非阻塞的获取锁操作, 如果可以获取则返回0,否则返回错误的EBUSY

2.5 代码讲解

代码说明1:读写锁基本应用

#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <bits/pthreadtypes.h> static pthread_rwlock_t rwlock; //读写锁对象 int count = 0; void *thread_function_read(void *arg)
{
while(1)
{
pthread_rwlock_rdlock(&rwlock);
printf("************************%d, read count %d\n", pthread_self(), count);
sleep(1);
pthread_rwlock_unlock(&rwlock);
usleep(100);
} return NULL;
} void *thread_function_write(void *arg)
{
while(1)
{
pthread_rwlock_wrlock(&rwlock);
count++;
printf("************************%d, write count %d\n", pthread_self(), count);
sleep(5);
pthread_rwlock_unlock(&rwlock);
usleep(100);
}
return NULL;
} int main(int argc, char *argv[])
{
pthread_t rpthread1, rpthread2, wpthread; pthread_rwlock_init(&rwlock,NULL); pthread_create(&rpthread1, NULL, thread_function_read, NULL);
pthread_create(&rpthread2, NULL, thread_function_read, NULL);
pthread_create(&wpthread, NULL, thread_function_write, NULL); pthread_join(rpthread1, NULL);
pthread_join(rpthread2, NULL);
pthread_join(wpthread, NULL); pthread_rwlock_destroy(&rwlock);
exit(EXIT_SUCCESS);
}

结果说明:

[root@rocket lock-free]#./pthread_rwlock

/* 2个读线程互相不阻塞 */

************************1442944768,read count 0

************************1432454912,read count 0

/* 写线程阻塞所有其它线程 */

************************1421965056,write count 1

************************1442944768,read count 1

************************1432454912,read count 1

************************1421965056,write count 2

************************1442944768,read count 2

************************1432454912,read count 2

************************1421965056,write count 3

************************1442944768,read count 3

************************1432454912,read count 3

************************1421965056,write count 4

有意思的是,加入去掉上面代码中thread_function_read和thread_function_write中的usleep(100),则会出现以下结果

[root@rocket lock-free]#./pthread_rwlock

************************-1896831232,read count 0

************************-1907321088,read count 0

************************-1907321088,read count 0

************************-1896831232,read count 0

************************-1907321088,read count 0

************************-1896831232,read count 0

************************-1907321088,read count 0

发现抢不到写锁,按我原先的理解,因为reader线程先启动,所以首先是reader抢到锁,reader抢到锁以后,writer阻塞在锁请求上,当reader释放以后,应该轮到writer才对啊,可是不是这样的!当reader释放后再次请求锁时,还是能拿到!writer基本抢不到锁!

查手册写到,"The pthread_rwlock_rdlock() function applies a read lock tothe read-write lock referenced by rwlock. The calling thread acquires the readlock if a writer does not hold the lock and there are no writers blocked on thelock. It is unspecified whether the calling thread acquires the lock when awriter does not hold the lock and there are writers waiting for the lock" 意思就是说,没有writer在等写锁的时辰,reader是可以拿到读锁的。然则没有划定,若是有writer在期待写锁,该若何?

还好,Linux有pthread_rwlockattr_setkind_np这个函数。

enum

{

PTHREAD_RWLOCK_PREFER_READER_NP,

PTHREAD_RWLOCK_PREFER_WRITER_NP,

PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP,

PTHREAD_RWLOCK_DEFAULT_NP =PTHREAD_RWLOCK_PREFER_READER_NP

};

可是直接pthread_rwlockattr_setkind_np(&attr,PTHREAD_RWLOCK_PREFER_WRITER_NP);

没用!为啥呢?连man页都没有,所以我思疑这个函数没实现,因而就用debuginfo-install glibc? 装glibc的调试符号,然后用gdb跟进去,发现pthread_rwlockattr_setkind_np确切是有实现的,代码很简单,更改了attr的一个成员变量。那是为啥呢?

再谷歌,终究找到了pthread_rwlockattr_setkind_np的man page,末尾有一段notes,让我年夜汗:

“Setting the value read-write lockkind to PTHREAD_RWLOCK_PREFER_WRITER_NP, results in the same behavior assetting the value to PTHREAD_RWLOCK_PREFER_READER_NP. As long as a readerthread holds the lock the thread holding a write lock will be starved. Settingthe kind value to PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, allows thewriter to run. However, the writer may not be recursive as is implied by thename. “

意思就是说,

PTHREAD_RWLOCK_PREFER_WRITER_NP和PTHREAD_RWLOCK_PREFER_READER_NP是一样滴!应当设置成PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP才对!可是PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP也是名存实亡滴,它才不会recursive 呢。

这样就有了代码说明2:读写锁优先级的使用

#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <bits/pthreadtypes.h> static pthread_rwlock_t rwlock; //读写锁对象 int count = 0; void *thread_function_read(void *arg)
{
while(1)
{
pthread_rwlock_rdlock(&rwlock);
printf("************************%d, read count %d\n", pthread_self(), count);
sleep(1);
pthread_rwlock_unlock(&rwlock);
//usleep(100);
} return NULL;
} void *thread_function_write(void *arg)
{
while(1)
{
pthread_rwlock_wrlock(&rwlock);
count++;
printf("************************%d, write count %d\n", pthread_self(), count);
sleep(1);
pthread_rwlock_unlock(&rwlock);
usleep(100);
}
return NULL;
} int main(int argc, char *argv[])
{
pthread_t rpthread1, rpthread2, wpthread; pthread_rwlockattr_t attr;
pthread_rwlockattr_setkind_np(&attr,PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
pthread_rwlock_init(&rwlock, &attr); pthread_create(&rpthread1, NULL, thread_function_read, NULL);
pthread_create(&rpthread2, NULL, thread_function_read, NULL);
pthread_create(&wpthread, NULL, thread_function_write, NULL); pthread_join(rpthread1, NULL);
pthread_join(rpthread2, NULL);
pthread_join(wpthread, NULL); pthread_rwlock_destroy(&rwlock);
exit(EXIT_SUCCESS);
}

运行结果:

[root@rocket lock-free]#./pthread_rwlock_withpriority

************************1529054976,read count 0

************************1518565120,read count 0

************************1508075264,write count 1

************************1529054976,read count 1

************************1518565120,read count 1

************************1508075264,write count 2

************************1529054976,read count 2

************************1518565120,read count 2

************************1508075264,write count 3

这样就不会导致writer饿死。

代码说明3:pthread_rwlock_tryrdlock使用

#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <bits/pthreadtypes.h> static pthread_rwlock_t rwlock; //读写锁对象 int count = 0; void *thread_function_read(void *arg)
{
int print_count = 0;
while(1)
{
if (pthread_rwlock_tryrdlock(&rwlock) == 0)
{
printf("************************%d, read count %d\n", pthread_self(), count);
sleep(1);
pthread_rwlock_unlock(&rwlock);
usleep(100);
}
else
{
print_count++;
if (print_count % 10 == 0)
{
printf("I have try!But i can`t lock the rdlock!\n");
print_count = 0;
} usleep(100);
}
} return NULL;
} void *thread_function_write(void *arg)
{
while(1)
{
pthread_rwlock_wrlock(&rwlock);
count++;
printf("************************%d, write count %d\n", pthread_self(), count);
sleep(5);
pthread_rwlock_unlock(&rwlock);
usleep(100);
}
return NULL;
} int main(int argc, char *argv[])
{
pthread_t rpthread1, rpthread2, wpthread; pthread_rwlock_init(&rwlock,NULL); pthread_create(&rpthread1, NULL, thread_function_read, NULL);
pthread_create(&rpthread2, NULL, thread_function_read, NULL);
pthread_create(&wpthread, NULL, thread_function_write, NULL); pthread_join(rpthread1, NULL);
pthread_join(rpthread2, NULL);
pthread_join(wpthread, NULL); pthread_rwlock_destroy(&rwlock);
exit(EXIT_SUCCESS);
}

结果说明:

************************1819674368,read count 0

************************1809184512,read count 0

************************1798694656,write count 1

/* trylock没有成功马上返回! */

I have try!But i can`t lock therdlock!

I have try!But i can`t lock therdlock!

I have try!But i can`t lock therdlock!

I have try!But i can`t lock therdlock!

************************1819674368,read count 1

************************1809184512,read count 1

************************1798694656, writecount 2

I have try!But i can`t lock therdlock!

I have try!But i can`t lock therdlock!

I have try!But i can`t lock therdlock!

I have try!But i can`t lock therdlock!

3 自旋锁

自旋锁是SMP架构中的一种low-level的同步机制。
当线程A想要获取一把自旋锁而该锁又被其它线程锁持有时,线程A会在一个循环中自旋以检测锁是不是已经可用了。对于自旋锁需要注意:

由于自旋时不释放CPU,因而持有自旋锁的线程应该尽快释放自旋锁,否则等待该自旋锁的线程会一直在那里自旋,这就会浪费CPU时间。

持有自旋锁的线程在sleep之前应该释放自旋锁以便其它线程可以获得自旋锁。(在内核编程中,如果持有自旋锁的代码sleep了就可能导致整个系统挂起)

Pthreads提供的与Spin Lock锁操作相关的API主要有:

intpthread_spin_destroy(pthread_spinlock_t *);

int pthread_spin_init(pthread_spinlock_t*, int);

intpthread_spin_lock(pthread_spinlock_t *);

intpthread_spin_trylock(pthread_spinlock_t *);

intpthread_spin_unlock(pthread_spinlock_t *);

3.1 初始化自旋锁

pthread_spin_init用来申请使用自旋锁所需要的资源并且将它初始化为非锁定状态。pshared的取值及其含义:

PTHREAD_PROCESS_SHARED:该自旋锁可以在多个进程中的线程之间共享。

PTHREAD_PROCESS_PRIVATE:仅初始化本自旋锁的线程所在的进程内的线程才能够使用该自旋锁。

3.2 获得一个自旋锁

pthread_spin_lock用来获取(锁定)指定的自旋锁. 如果该自旋锁当前没有被其它线程所持有,则调用该函数的线程获得该自旋锁.否则该函数在获得自旋锁之前不会返回。如果调用该函数的线程在调用该函数时已经持有了该自旋锁,则结果是不确定的。

3.3 尝试获取一个自旋锁

pthread_spin_trylock会尝试获取指定的自旋锁,如果无法获取则理解返回失败。

3.4 释放(解锁)一个自旋锁

pthread_spin_unlock用于释放指定的自旋锁。

3.5 销毁一个自旋锁

pthread_spin_destroy用来销毁指定的自旋锁并释放所有相关联的资源(所谓的所有指的是由pthread_spin_init自动申请的资源)在调用该函数之后如果没有调用pthread_spin_init重新初始化自旋锁,则任何尝试使用该锁的调用的结果都是未定义的。如果调用该函数时自旋锁正在被使用或者自旋锁未被初始化则结果是未定义的。

4 特性对比

锁类型

锁特性

适用场景

互斥锁mutex

会导致线程切换

一般情况下的首选

读写锁rwlock

同一时间只能有一个writer

可以同时有多个reader

读多写少的场景

自旋锁spinlock

不会导致线程切换

会导致CPU利用率升高

适合小代码段

小代码段,加锁不是很频繁的场景

版权声明:本文为博主原创文章,未经博主允许不得转载。

Linux同步机制(一) - 线程锁的更多相关文章

  1. 【av68676164(p31-p32)】Windows和Linux同步机制

    4.6.1 Windows同步机制 临界区(CRITICAL_SECTION) 在进程内使用,保证仅一个线程可以申请到该对象 临界区内是临界资源的访问 相关的API函数 初始化临界区 WINBASEA ...

  2. Linux同步机制(二) - 条件变量,信号量,文件锁,栅栏

    1 条件变量 条件变量是一种同步机制,允许线程挂起,直到共享数据上的某些条件得到满足. 1.1 相关函数 #include <pthread.h>  pthread_cond_t cond ...

  3. linux 同步机制之complete【转】

    转自: http://blog.csdn.net/wealoong/article/details/8490654 在Linux内核中,completion是一种简单的同步机制,标志"thi ...

  4. linux同步机制

    很早之前就接触过同步这个概念了,但是一直都很模糊,没有深入地学习了解过,近期有时间了,就花时间研习了一下<linux内核标准教程>和<深入linux设备驱动程序内核机制>这两本 ...

  5. 对JavaScript中异步同步机制以及线程深入了解

    今天在网上看到各种对Js异步同步单线程多线程的讨论 经过前辈们的洗礼 加上鄙人小小的理解 就来纸上谈兵一下吧~ Js本身就是单线程的 至于为什么Js是单线程的 那就要追溯到Js的历史了 总而言之 由于 ...

  6. Linux同步机制 - 多线程开发总结

    1 对于CPU开销大的场景,能利用多核,就尽量利用多核(常常自以为某需求的运算量不大,且CPU足够快,就偷懒写个单线程,结果效率很低) 2 使用多线程的时候,默认是加锁的.在加锁保证业务正常的条件下, ...

  7. Linux同步机制 - 基本概念(死锁,活锁,饿死,优先级反转,护航现象)

    死锁(deadlock) 是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进 ...

  8. linux同步机制2

    一.并发控制(1)自旋锁得不到资源,会原地打转,直到获得资源为止定义自旋锁 spinlock_t spin;初始化自旋锁 spin_lock_init(lock);获得自旋锁spin_lock(loc ...

  9. 阶段1 语言基础+高级_1-3-Java语言高级_05-异常与多线程_第3节 线程同步机制_1_线程安全问题的概述

随机推荐

  1. Asp.net与Flex交互测试记录

    一.利用asp.net为Flex提供数据服务,flex为前端表现. 二.flex通过三种方式四种代码实现来取数据.分别为     HttpService. WebService. RemoteObje ...

  2. Asp.net MVC 实现图片上传剪切

    使用技术:Asp.net MVC与jquery.uploadify,Jcrop 首先上页面 01 <strong><!DOCTYPE html> 02  <html> ...

  3. DirectShow 最简单的入门 -- 播放一段视频

    #include <dshow.h> #pragma comment(lib,"strmbase.lib") #pragma comment(lib,"qua ...

  4. [大牛翻译系列]Hadoop(5)MapReduce 排序:次排序(Secondary sort)

    4.2 排序(SORT) 在MapReduce中,排序的目的有两个: MapReduce可以通过排序将Map输出的键分组.然后每组键调用一次reduce. 在某些需要排序的特定场景中,用户可以将作业( ...

  5. 在 Java 中如何更高效地存储和管理 SQL 语句?

    [编者按]还在为管理 Java 代码中的 SQL 语句而烦恼吗?让 Zemian 帮你摆脱困境吧!本文系 OneAPM 工程师编译整理 注意:使用java.util.Properties#loadFr ...

  6. HTML5程序设计--SVG

    SVG(Scalable Vector Graphics):可缩放矢量图形,一种二维图形表示语言. 借助SVG,我们可以实现很多同Canvas API类型的绘制操作,但在Canvas元素上绘制文本的时 ...

  7. (转)排列算法 Permutation Generation

    转自:http://www.cnblogs.com/dragonpig/archive/2010/01/21/1653680.html http://www.notesandreviews.com/p ...

  8. Spinner学习

    我暂且把Spinner称作下拉选择框吧,先来看一下它的效果: 在layout文件中添加Spinner的代码如下: <Spinner android:id="@+id/planets_s ...

  9. iScroll.js 用法参考

    本文原文链接:http://www.cnblogs.com/duanhuajian/archive/2013/04/08/3008323.html 概要 iScroll 4 这个版本完全重写了iScr ...

  10. JS中的this好神奇,都把我弄晕了

    一.this的常见判断: 1.函数预编译过程 this —> window 2.全局作用域里 this —> window 3.call/apply 可以改变函数运行时this指向 4.o ...