由adsl多拨信号量机制探讨

网上看到一篇文章.通过修改pppd源码来实现adsl多拨的目的.由此引发了我对进程间同步的兴趣.于是研究了一番linux下进程间同步.

是这样的应用场景,在pppoe最后的阶段,客户端response给服务器的最后阶段,如果有多个pppd进行拨号.同时进行到这一阶段而同时把最后的response发送给服务器.就可以多拨成功.所以问题的关键就是多进程的同步.涉及到以下几个系统调用

一. int semget(key_t key, int nsems, int semflg);

1. key_t key,其它进程得到这个信号量需要这个key,一般用ftok来生成

#define KEY_PATH /path/to/file

#define KEY_PRI_NUM

int sem_key;

sem_key = ftok(KEY_PATH, KEY_PRI_NUM);

返回信号量的标识符

2. int nsems,信号量集包含的信号量的个数,这里是1

3. int sem_flg, 标志位.可以是IPC_CREAT,IPC_EXCL,如果设置了IPC_EXCL,则对于已经存在的信号量会返回错误,如果只设了IPC_CREAT对于已经存在的会返回当前信号量标识符,如果不存在则会创建信号号集,并返回标识符

二. int semctl(int semid, int semnum, int cmd,…)

1. int semid,信号量的标识符

2. int semnum,信号量在信号量集中偏移位置

3. int cmd,这个是你想要执行的命令,可以用来获取信号量的状态,我的需求是设置信号量的值,所以cmd就为SETVAL,

4.第4个参数是根据cmd的值来设置的。如果cmd是GETVAL,则不需要第四个参数,如果是SETVAL则调用程序需要声明以下联合体

union semun {

int val; /* Value for SETVAL */

struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */

unsigned short *array; /* Array for GETALL, SETALL */

struct seminfo *__buf; /* Buffer for IPC_INFO

(Linux-specific) */

};

三 int semop(int semid, struct sembuf *sops, unsigned nsops)

1. semid: 是通过semget获取到的id

2. sembuf

struct sembuf {

unsigned short sem_num; /* semaphore number */

short sem_op; /* semaphore operation */

short sem_flg; /* operation flags */

}

如果sem_op为0,则是一个等待信号量为0的过程。 当信号量的值为0时。程序就会继续执行。

写了一个小程序。模拟这个过程:

sem.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

#define KEY_PATH "/usr/bin/"
#define KEY_PRI 123

#define SEM_NUM 1

key_t key;

union semun {
int              val;    /* Value for SETVAL */
struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
unsigned short  *array;  /* Array for GETALL, SETALL */
struct seminfo  *__buf;  /* Buffer for IPC_INFO (Linux-specific) */
};

union semun arg;
int main(int argc, char* argv[]) {
int sem_id;
int ret;
key = ftok(KEY_PATH, KEY_PRI);
if (-1 == key) {
perror("fail to get key\n");
return -1;
}

sem_id = semget(key, SEM_NUM, IPC_CREAT|0660);
if (-1 == sem_id) {
perror("fail semget\n");
return -1;
}

arg.val = 5;
//incre 5
ret = semctl(sem_id, 0, SETVAL, arg);
if (-1 == ret) {
perror("fail semctl\n");
return -1;
}

sleep(1000);
return 0;
}

sem_c.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

#define KEY_PATH "/usr/bin/"
#define KEY_PRI 123

#define SEM_NUM 1

key_t key;

struct sembuf sb={0, -1, 0};

int main(int argc, char* argv[]) {
int sem_id;
int ret;
key = ftok(KEY_PATH, KEY_PRI);
if (-1 == key) {
perror("fail to get key\n");
return -1;
}

sem_id = semget(key, SEM_NUM, IPC_CREAT|0660);
if (-1 == sem_id) {
perror("fail semget\n");
return -1;
}

ret = semctl(sem_id, 0, GETVAL);
if (-1 == ret) {
perror("semctl fail\n");
return -1;
}

printf("semct: %d\n", ret);
//decrement
ret = semop(sem_id, &amp;sb, 1);
if (-1 == ret) {
perror("semop fail\n");
return -1;
}

//wait for 0
sb.sem_op = 0;
ret = semop(sem_id, &amp;sb, 1);
if (-1 == ret) {
perror("semop fail\n");
return -1;
}

printf("ha");

return 0;
}