免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1123 | 回复: 0
打印 上一主题 下一主题

linux内核信号量学习(2.6.23(i386)) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-07-31 21:10 |只看该作者 |倒序浏览

       
       
一、定义:
/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
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP