- 论坛徽章:
- 0
|
一、定义:
/linux/include/asm-i386/semaphore.h
[color="#000080"] [color="#000080"]44
struct
semaphore
{
[color="#000080"] [color="#000080"]45
atomic_t
count
;
[color="#000080"] [color="#000080"]46
int
sleepers
;
[color="#000080"] [color="#000080"]47
wait_queue_head_t
wait
;
[color="#000080"] [color="#000080"]48
};
二、作用:
[color="#000000"]Linux中的信号量是一种睡眠锁。如果有一个任务试图获得一个已被持有的信号量时,信号量会将其推入等待队列,然后让其睡眠。这时处理器获得自由去执行其它代码。当持有信号量的进程将信号量释放后,在等待队列中的一个任务将被唤醒,从而便可以获得这个信号量
[color="#000000"]。主要用在[color="#000000"]linux内核中的同步和互斥。
[color="#000000"]三、字段详解:
[color="#000000"]1、atomic_t
count;
[color="#000000"]typedef struct { int
counter
[color="#000000"]; }
atomic_t
[color="#000000"];
[color="#000000"]在此根据[color="#000000"]count.counter的值不同该字段代表不同的意义:
[color="#000000"](1)如果[color="#000000"]count.counter大于[color="#000000"]0,则资源是空闲的,该资源现在可以被使用。
[color="#000000"](2)如果[color="#000000"]count.counter等于[color="#000000"]0,则信号量是忙的,但没有进程等待这个被保护的资源,当前只有该进程在访问被保护的资源。
[color="#000000"](3)如果[color="#000000"]count.counter小于[color="#000000"]0,则该资源不可用,并且至少有一个进程在等待该资源。
[color="#000000"]2、int
sleepers;
[color="#000000"]存放一个标志,表示是否有一些进程在信号量上睡眠。在获取信号量操作的时候,使用该字段和[color="#000000"]count字段来判断信号量的状态和进行不同的操作。
[color="#000000"]3、[color="#000000"]wait_queue_head_t;
[color="#000080"] [color="#000080"]50
[color="#000000"]struct
__wait_queue_head
[color="#000000"] {
[color="#000080"] [color="#000080"]51
spinlock_t
lock
;
[color="#000080"] [color="#000080"]52
struct
list_head
task_list
;
[color="#000080"] [color="#000080"]53
};
[color="#000080"] [color="#000080"]54
typedef struct
__wait_queue_head
wait_queue_head_t
;
[color="#000000"]task_list字段存放当前等待该信号量的所有进程的链表。如果[color="#000000"]count.counter大于或等于[color="#000000"]0,该链表就为空。
[color="#000000"]四、特点:
信号量的睡眠特性,使得信号量适用于锁会被长时间持有的情况;只能在进程上下文中使用,因为中断上下文中是不能被调度的;另外当代码持有信号量时,不可以再持有自旋锁。
[color="#000000"]一个任务要想访问共享资源,首先必须得到信号量,获取信号量的操作将把信号量的值减[color="#000000"]1,若当前信号量的值为负数,表明无法获得信号量,该任务必须挂起在该信号量的等待队列等待该信号量可用;若当前信号量的值为非负数,表示可以获得信号量,因而可以立刻访问被该信号量保护的共享资源。当任务访问完被信号量保护的共享资源后,必须释放信号量,释放信号量通过把信号量的值加[color="#000000"]1实现,如果信号量的值为非正数,表明有任务等待当前信号量,因此它也唤醒所有等待该信号量的任务。
[color="#000000"]五、操作:
[color="#000000"]1、定义及初始化:
[color="#000000"](1)
struct
semapom sem;
[color="#000000"]sema_init(&sem,1);
[color="#000000"]直接定义一个信号量[color="#000000"]sem,并调用[color="#000000"]sema_init()对其进行初始化:
64
[color="#000000"]static
inline
[color="#000000"] void
sema_init
[color="#000000"] (struct
semaphore
[color="#000000"] *
sem
[color="#000000"], int
val
[color="#000000"])
65
{
[color="#000080"] [color="#000080"]66
/*
[color="#000080"] [color="#000080"]67
* *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val);
[color="#000080"] [color="#000080"]68
*
[color="#000080"] [color="#000080"]69
* i'd rather use the more flexible initialization above, but sadly
[color="#000080"] [color="#000080"]70
* GCC 2.7.2.3 emits a bogus warning. EGCS doesn't. Oh well.
[color="#000080"] [color="#000080"]71
*/
[color="#000080"] [color="#000080"]72
atomic_set
(&
sem
->
count
,
val
);
[color="#000080"] [color="#000080"]73
sem
->
sleepers
= 0;
[color="#000080"] [color="#000080"]74
init_waitqueue_head
(&
sem
->
wait
);
[color="#000080"] [color="#000080"]75
}
[color="#000000"]该函数会将[color="#000000"]sem->count.counter初始化为[color="#000000"]val。虽然[color="#000000"]val可以为任何整数,但通常会取[color="#000000"]1、[color="#000000"]0。并置[color="#000000"]sleepers为[color="#000000"]0,[color="#000000"]sem->wait.task_list为空链表。
[color="#000000"](2)
srtuct
semaphore sem;
[color="#000000"]init_MUTEX(&sem);
[color="#000000"]直接定义信号量[color="#000000"]sem并初始化为互斥信号量。
[color="#000080"] [color="#000080"]77
[color="#000000"]static
inline
[color="#000000"] void
init_MUTEX
[color="#000000"] (struct
semaphore
[color="#000000"] *
sem
[color="#000000"])
[color="#000080"] [color="#000080"]78
{
[color="#000080"] [color="#000080"]79
sema_init
(
sem
, 1);
[color="#000080"] [color="#000080"]80
}
[color="#000000"]该函数直接将信号量的[color="#000000"]count.counter置为[color="#000000"]1,便是初始化一个用于互斥访问的信号量。也就是说被保护的资源不能同时被多个进程访问,此刻资源是空闲的,那么当有一个进程访问该资源时,也即获得了信号量,当再有进程到来且当前访问资源的进程没有释放信号量时,后来的进程是不能访问该资源的。此刻它被置入信号量的等待进程队列,并进入休眠状态。
[color="#000000"](3)
struct
semaphore sem;
[color="#000000"]init_MUTEX_LOCKED(&sem);
[color="#000000"]直接定义信号量[color="#000000"]sem并初始化为资源忙状态,用于同步。
[color="#000080"] [color="#000080"]82
[color="#000000"]static
inline
[color="#000000"] void
init_MUTEX_LOCKED
[color="#000000"] (struct
semaphore
[color="#000000"] *
sem
[color="#000000"])
[color="#000080"] [color="#000080"]83
{
[color="#000080"] [color="#000080"]84
sema_init
(
sem
, 0);
[color="#000080"] [color="#000080"]85
}
[color="#000000"]也就是说当前该信号量已经被锁定,一个执行单元的继续执行需等待另一执行单元完成,保证执行的先后顺序。例如:
[color="#000000"]进程[color="#000000"]A 进程[color="#000000"]B
struct
semaphore sem; ...[CODE 2]...
[color="#000000"]init_MUTEX_LOCKED(&sem); up(&sem);
...[CODE
1]...
[color="#000000"]down(&sem);
...[CODE
3]...
[color="#000000"]如上,进程[color="#000000"]A先运行,运行到[color="#000000"]down(&sem);的时候发现信号量为资源忙状态,不能获得,于是被置入信号量的等待队列中。当进程[color="#000000"]B执行完CODE
2代码段到[color="#000000"]up(&sem)时,会释放信号量,发现进程[color="#000000"]A在等待信号量,就将[color="#000000"]A从等待队列中删除,并唤醒[color="#000000"]A。这样就保证了代码的执行顺序是CODE
1 → CODE 2 → CODE 3。实现了同步。
[color="#000000"](4)
[color="#000000"]DECLARE_MUTEX(sem);
[color="#000000"]DECLARE_MUTEX_LOCKED(sem);
[color="#000080"] [color="#000080"]51
[color="#000000"]#define
__SEMAPHORE_INITIALIZER
[color="#000000"](
name
[color="#000000"],
n
[color="#000000"]) \
[color="#000080"] [color="#000080"]52
{ \
[color="#000080"] [color="#000080"]53
.
count
=
ATOMIC_INIT
(
n
), \
[color="#000080"] [color="#000080"]54
.
sleepers
= 0, \
[color="#000080"] [color="#000080"]55
.
wait
=
__WAIT_QUEUE_HEAD_INITIALIZER
((
name
).
wait
) \
[color="#000080"] [color="#000080"]56
}
[color="#000080"] [color="#000080"]57
[color="#000080"] [color="#000080"]58
#define
__DECLARE_SEMAPHORE_GENERIC
(
name
,
count
) \
[color="#000080"] [color="#000080"]59
struct
semaphore
name
=
__SEMAPHORE_INITIALIZER
(
name
,
count
)
[color="#000080"] [color="#000080"]60
[color="#000080"] [color="#000080"]61
#define
DECLARE_MUTEX
(
name
)
__DECLARE_SEMAPHORE_GENERIC
(
name
,1)
[color="#000080"] [color="#000080"]62
#define
DECLARE_MUTEX_LOCKED
(
name
)
__DECLARE_SEMAPHORE_GENERIC
(
name
,0)
[color="#000000"]此两个宏都是定义初始化信号量。[color="#000000"]DECLARE_MUTEX()等同于以上所讲的第二个,[color="#000000"]DECLARE_MUTEX_LOCKED()等同于以上所讲的第三个。
[color="#000000"]2、获得信号量:
[color="#000000"](1)
[color="#000080"] [color="#000080"]97
[color="#000000"]static
inline
[color="#000000"] void
down
[color="#000000"](struct
semaphore
[color="#000000"] *
sem
[color="#000000"])
[color="#000080"] [color="#000080"]98
{
[color="#000080"] [color="#000080"]99
might_sleep
();
[color="#000080"] [color="#000080"]100
__asm__
__volatile__
(
[color="#000080"] [color="#000080"]101
"# atomic down operation\n\t"
[color="#000080"] [color="#000080"]102
LOCK_PREFIX
"decl %0\n\t" /* --sem->count */
[color="#000080"] [color="#000080"]103
"jns 2f\n"
[color="#000080"] [color="#000080"]104
"\tlea %0,%%eax\n\t"
[color="#000080"] [color="#000080"]105
"call __down_failed\n"
[color="#000080"] [color="#000080"]106
"2:"
[color="#000080"] [color="#000080"]107
:"+m" (
sem
->
count
)
[color="#000080"] [color="#000080"]108
:
[color="#000080"] [color="#000080"]109
:"memory","ax");
[color="#000080"] [color="#000080"]110
}
[color="#000080"] [color="#000080"]64
void
__sched
[color="#000080"] [color="#000080"]65
__down_failed
(struct
semaphore
*
sem
)
[color="#000080"] [color="#000080"]66
{
[color="#000080"] [color="#000080"]67
struct
task_struct
*
tsk
=
current
;
[color="#000080"] [color="#000080"]68
DECLARE_WAITQUEUE
(
wait
,
tsk
);
[color="#000080"] [color="#000080"]69
[color="#000080"] [color="#000080"]70
#ifdef
CONFIG_DEBUG_SEMAPHORE
[color="#000080"] [color="#000080"]71
printk
("%s(%d): down failed(%p)\n",
[color="#000080"] [color="#000080"]72
tsk
->
comm
,
tsk
->
pid
,
sem
);
[color="#000080"] [color="#000080"]73
#endif
[color="#000080"] [color="#000080"]74
[color="#000080"] [color="#000080"]75
tsk
->
state
=
TASK_UNINTERRUPTIBLE
;
[color="#000080"] [color="#000080"]76
wmb
();
[color="#000080"] [color="#000080"]77
add_wait_queue_exclusive
(&
sem
->
wait
, &
wait
);
[color="#000080"] [color="#000080"]78
[color="#000080"] [color="#000080"]79
/*
[color="#000080"] [color="#000080"]80
* Try to get the semaphore. If the count is > 0, then we've
[color="#000080"] [color="#000080"]81
* got the semaphore; we decrement count and exit the loop.
[color="#000080"] [color="#000080"]82
* If the count is 0 or negative, we set it to -1, indicating
[color="#000080"] [color="#000080"]83
* that we are asleep, and then sleep.
[color="#000080"] [color="#000080"]84
*/
[color="#000080"] [color="#000080"]85
while (
__sem_update_count
(
sem
, -1)
[color="#000080"] [color="#000080"]86
schedule
();
[color="#000080"] [color="#000080"]87
set_task_state
(
tsk
,
TASK_UNINTERRUPTIBLE
);
[color="#000080"] [color="#000080"]88
}
[color="#000080"] [color="#000080"]89
remove_wait_queue
(&
sem
->
wait
, &
wait
);
[color="#000080"] [color="#000080"]90
tsk
->
state
=
TASK_RUNNING
;
[color="#000080"] [color="#000080"]91
[color="#000080"] [color="#000080"]92
/*
[color="#000080"] [color="#000080"]93
* If there are any more sleepers, wake one of them up so
[color="#000080"] [color="#000080"]94
* that it can either get the semaphore, or set count to -1
[color="#000080"] [color="#000080"]95
* indicating that there are still processes sleeping.
[color="#000080"] [color="#000080"]96
*/
[color="#000080"] [color="#000080"]97
wake_up
(&
sem
->
wait
);
[color="#000080"] [color="#000080"]98
[color="#000080"] [color="#000080"]99
#ifdef
CONFIG_DEBUG_SEMAPHORE
[color="#000080"] [color="#000080"]100
printk
("%s(%d): down acquired(%p)\n",
[color="#000080"] [color="#000080"]101
tsk
->
comm
,
tsk
->
pid
,
sem
);
[color="#000080"] [color="#000080"]102
#endif
[color="#000080"] [color="#000080"]103
}
[color="#000000"]从代码中可知:
[color="#000000"] 如果[color="#000000"]count.counter为[color="#000000"]1,则置[color="#000000"]count.counter为[color="#000000"]0,直接跳出函数。
[color="#000000"] 如果[color="#000000"]count.counter为[color="#000000"]0,[color="#000000"]count.counter被减为-[color="#000000"]1,之后执行[color="#000000"]__down_failed()函数。
[color="#000000"]__down_failed()函数首先将当前进程设置为不可中断状态[color="#000000"](
TASK_UNINTERRUPTIBLE
[color="#000000"])然后将其添加进等待进程队列,接下来在[color="#000000"]whlie循环处试图获得信号量。如果[color="#000000"]count.counter大于[color="#000000"]0就获得了信号量,则不进入循环,将当前进程从等待队列中删除,并设置其状态为可运行状态[color="#000000"](TASK_RUNNING),最后唤醒等待该信号量的进程[color="#000000"](此处初始[color="#000000"]count.counter为[color="#000000"]0,表示没有等待进程,所以此句相当于没有[color="#000000"])。否则将[color="#000000"]count.counter设置为-[color="#000000"]1,并进入[color="#000000"]whlie循环,挂起当前进程,随后又恢复,继续测试[color="#000000"]count.counter字段直到其大于[color="#000000"]0(即获得信号量[color="#000000"])。
[color="#000000"] 如果[color="#000000"]count.counter为-[color="#000000"]1,则其被置为-[color="#000000"]2,之后执行[color="#000000"]__down_failed()函数。与[color="#000000"]count.counter等于[color="#000000"]0不同的是其在获得了信号量之后,由于有等待进程[color="#000000"](count.counter=-1),所以退出时会唤醒等待进程。
[color="#000000"] 由于信号量会导致睡眠,所以不能用在中断上下文。再者使用[color="#000000"]down()而进入睡眠的进程不能被信号打断。
[color="#000000"](2)
[color="#000080"] [color="#000080"]112
[color="#000000"]/*
[color="#000080"] [color="#000080"]113
* Interruptible try to acquire a semaphore. If we obtained
[color="#000080"] [color="#000080"]114
* it, return zero. If we were interrupted, returns -EINTR
[color="#000080"] [color="#000080"]115
*/
[color="#000080"] [color="#000080"]116
static
inline
int
down_interruptible
(struct
semaphore
*
sem
)
[color="#000080"] [color="#000080"]117
{
[color="#000080"] [color="#000080"]118
int
result
;
[color="#000080"] [color="#000080"]119
[color="#000080"] [color="#000080"]120
might_sleep
();
[color="#000080"] [color="#000080"]121
__asm__
__volatile__
(
[color="#000080"] [color="#000080"]122
"# atomic interruptible down operation\n\t"
[color="#000080"] [color="#000080"]123
"xorl %0,%0\n\t"
[color="#000080"] [color="#000080"]124
LOCK_PREFIX
"decl %1\n\t" /* --sem->count */
[color="#000080"] [color="#000080"]125
"jns 2f\n\t"
[color="#000080"] [color="#000080"]126
"lea %1,%%eax\n\t"
[color="#000080"] [color="#000080"]127
"call __down_failed_interruptible\n"
[color="#000080"] [color="#000080"]128
"2:"
[color="#000080"] [color="#000080"]129
:"=&a" (
result
), "+m" (
sem
->
count
)
[color="#000080"] [color="#000080"]130
:
[color="#000080"] [color="#000080"]131
:"memory");
[color="#000080"] [color="#000080"]132
return
result
;
[color="#000080"] [color="#000080"]133
}
[color="#000080"] [color="#000080"]105
[color="#000000"]int
__sched
[color="#000080"] [color="#000080"]106
__down_failed_interruptible
(struct
semaphore
*
sem
)
[color="#000080"] [color="#000080"]107
{
[color="#000080"] [color="#000080"]108
struct
task_struct
*
tsk
=
current
;
[color="#000080"] [color="#000080"]109
DECLARE_WAITQUEUE
(
wait
,
tsk
);
[color="#000080"] [color="#000080"]110
long
ret
= 0;
[color="#000080"] [color="#000080"]111
[color="#000080"] [color="#000080"]112
#ifdef
CONFIG_DEBUG_SEMAPHORE
[color="#000080"] [color="#000080"]113
printk
("%s(%d): down failed(%p)\n",
[color="#000080"] [color="#000080"]114
tsk
->
comm
,
tsk
->
pid
,
sem
);
[color="#000080"] [color="#000080"]115
#endif
[color="#000080"] [color="#000080"]116
[color="#000080"] [color="#000080"]117
tsk
->
state
=
TASK_INTERRUPTIBLE
;
[color="#000080"] [color="#000080"]118
wmb
();
[color="#000080"] [color="#000080"]119
add_wait_queue_exclusive
(&
sem
->
wait
, &
wait
);
[color="#000080"] [color="#000080"]120
[color="#000080"] [color="#000080"]121
while (
__sem_update_count
(
sem
, -1)
[color="#000080"] [color="#000080"]122
if (
signal_pending
(
current
)) {
[color="#000080"] [color="#000080"]123
/*
[color="#000080"] [color="#000080"]124
* A signal is pending - give up trying.
[color="#000080"] [color="#000080"]125
* Set sem->count to 0 if it is negative,
[color="#000080"] [color="#000080"]126
* since we are no longer sleeping.
[color="#000080"] [color="#000080"]127
*/
[color="#000080"] [color="#000080"]128
__sem_update_count
(
sem
, 0);
[color="#000080"] [color="#000080"]129
ret
= -
EINTR
;
[color="#000080"] [color="#000080"]130
break;
[color="#000080"] [color="#000080"]131
}
[color="#000080"] [color="#000080"]132
schedule
();
[color="#000080"] [color="#000080"]133
set_task_state
(
tsk
,
TASK_INTERRUPTIBLE
);
[color="#000080"] [color="#000080"]134
}
[color="#000080"] [color="#000080"]135
[color="#000080"] [color="#000080"]136
remove_wait_queue
(&
sem
->
wait
, &
wait
);
[color="#000080"] [color="#000080"]137
tsk
->
state
=
TASK_RUNNING
;
[color="#000080"] [color="#000080"]138
wake_up
(&
sem
->
wait
);
[color="#000080"] [color="#000080"]139
[color="#000080"] [color="#000080"]140
#ifdef
CONFIG_DEBUG_SEMAPHORE
[color="#000080"] [color="#000080"]141
printk
("%s(%d): down %s(%p)\n",
[color="#000080"] [color="#000080"]142
current
->
comm
,
current
->
pid
,
[color="#000080"] [color="#000080"]143
(
ret
sem
);
[color="#000080"] [color="#000080"]144
#endif
[color="#000080"] [color="#000080"]145
return
ret
;
[color="#000080"] [color="#000080"]146
}
[color="#000000"]由代码可以看出[color="#000000"]down_interruptible()和[color="#000000"]down()不同的是:[color="#000000"]down_interruptible()有返回值,
[color="#000000"]在调用[color="#000000"]__down_failed_interruptible()函数时[color="#000000"],[color="#000000"]while循环中稍有不同。[color="#000000"]__down_failed_interruptible()在[color="#000000"]while中时,如果收到[color="#000000"]TIF_SIGPENDING信号时,会置[color="#000000"]count.counter为[color="#000000"]0,跳出循环,可见[color="#000000"]down_interruptible()是可以被信号打断的,且返回非零[color="#000000"](EINIR)。
[color="#000000"](3)
[color="#000080"] [color="#000080"]139
[color="#000000"]static
inline
[color="#000000"] int
down_trylock
[color="#000000"](struct
semaphore
[color="#000000"] *
sem
[color="#000000"])
[color="#000080"] [color="#000080"]140
{
[color="#000080"] [color="#000080"]141
int
result
;
[color="#000080"] [color="#000080"]142
[color="#000080"] [color="#000080"]143
__asm__
__volatile__
(
[color="#000080"] [color="#000080"]144
"# atomic interruptible down operation\n\t"
[color="#000080"] [color="#000080"]145
"xorl %0,%0\n\t"
[color="#000080"] [color="#000080"]146
LOCK_PREFIX
"decl %1\n\t" /* --sem->count */
[color="#000080"] [color="#000080"]147
"jns 2f\n\t"
[color="#000080"] [color="#000080"]148
"lea %1,%%eax\n\t"
[color="#000080"] [color="#000080"]149
"call __down_failed_trylock\n\t"
[color="#000080"] [color="#000080"]150
"2:\n"
[color="#000080"] [color="#000080"]151
:"=&a" (
result
), "+m" (
sem
->
count
)
[color="#000080"] [color="#000080"]152
:
[color="#000080"] [color="#000080"]153
:"memory");
[color="#000080"] [color="#000080"]154
return
result
;
[color="#000080"] [color="#000080"]155
}
[color="#000000"] 该函数尝试获得信号量[color="#000000"]sem,如果能够立即获得,则获得信号量[color="#000000"]sem并返回[color="#000000"]0,否则,返回非[color="#000000"]0。它不会导致调用者睡眠,可以在中断上下文使用。
[color="#000000"]3、释放信号量:
[color="#000080"] [color="#000080"]168
[color="#000000"]static
inline
[color="#000000"] void
up
[color="#000000"](struct
semaphore
[color="#000000"] *
sem
[color="#000000"])
[color="#000080"] [color="#000080"]169
{
[color="#000080"] [color="#000080"]170
__asm__
__volatile__
(
[color="#000080"] [color="#000080"]171
"# atomic up operation\n\t"
[color="#000080"] [color="#000080"]172
LOCK_PREFIX
"incl %0\n\t" /* ++sem->count */
[color="#000080"] [color="#000080"]173
"jg 1f\n\t"
[color="#000080"] [color="#000080"]174
"call __up_wakeup\n"
[color="#000080"] [color="#000080"]175
"1:"
[color="#000080"] [color="#000080"]176
:"=m" (
sem
->
count
)
[color="#000080"] [color="#000080"]177
:"D" (
sem
)
[color="#000080"] [color="#000080"]178
:"memory");
[color="#000080"] [color="#000080"]179
}
[color="#000080"] [color="#000080"]148
[color="#000000"]void
[color="#000080"] [color="#000080"]149
__up_wakeup
(struct
semaphore
*
sem
)
[color="#000080"] [color="#000080"]150
{
[color="#000080"] [color="#000080"]151
/*
[color="#000080"] [color="#000080"]152
* Note that we incremented count in up() before we came here,
[color="#000080"] [color="#000080"]153
* but that was ineffective since the result was
[color="#000080"] [color="#000080"]154
* any negative value of count is equivalent to 0.
[color="#000080"] [color="#000080"]155
* This ends up setting count to 1, unless count is now > 0
[color="#000080"] [color="#000080"]156
* (i.e. because some other cpu has called up() in the meantime),
[color="#000080"] [color="#000080"]157
* in which case we just increment count.
[color="#000080"] [color="#000080"]158
*/
[color="#000080"] [color="#000080"]159
__sem_update_count
(
sem
, 1);
[color="#000080"] [color="#000080"]160
wake_up
(&
sem
->
wait
);
[color="#000080"] [color="#000080"]161
}
[color="#000000"]up()函数首先使[color="#000000"]count.counter自增,如果其大于[color="#000000"]0,则,说明其初始值是[color="#000000"]0,没有等待进程,所以直接跳出。否则调用[color="#000000"]__up_wake_up()函数将[color="#000000"]count.counter置为[color="#000000"]1,再唤醒等待进程。
[color="#000000"]六、使用实例:
[color="#000000"]信号量的一般使用形式是:
[color="#000000"]DECLARE_MUTEX(sem);
down(&sem);
//获得信号量
...[CODE]...
//临界区[color="#000000"](被保护的资源[color="#000000"])
up(&sem);
//释放信号量
七、信号量与自旋锁的比较:
信号量是进程级别的,用于多个进程之间对资源的互斥,虽然也是在内核中,但是该内核执行路径是以进程的身份,代表进程来竞争资源的。如果竞争失败,就会发生进程上下文切换,当前进程进入睡眠状态,CPU将运行其他进程。鉴于进程上下文切换的开销也很大,因此只有当进程占用资源时间较长时,用信号量才是较好的选择。当所要保护的临界区访问时间比较短时,用自旋锁是非常方便的,因为它节省上下文切换的时间。但是CPU得不到自旋锁会在那里空转知道其他执行单元解锁为止。所以要求锁不能在临界区里常时间停留,否则会降低系统的效率。
[color="#000000"] 自旋锁对信号量[color="#000000"]
------------------------------------------------------
需求
[color="#000000"] 建议的加锁方法[color="#000000"]
低开销加锁[color="#000000"] 优先使用自旋锁[color="#000000"]
短期锁定[color="#000000"] 优先使用自旋锁[color="#000000"]
长期加锁[color="#000000"] 优先使用信号量[color="#000000"]
中断上下文中加锁[color="#000000"] 使用自旋锁[color="#000000"]
持有锁是需要睡眠、调度[color="#000000"] 使用信号量
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/73528/showart_1098606.html |
|