当前位置:文档之家› linux信号量机制

linux信号量机制

linux信号量机制
linux信号量机制

linux信号量机制(semaphore)

信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问。当公共资源增加时,调用函数sem_post()增加信号量。只有当信号量值大于0时,才能使用公共资源,使用后,函数sem_wait()减少信号量。函数sem_trywait()和函数pthread_ mutex_trylock()起同样的作用,它是函数sem_wait()的非阻塞版本。它们都在头文件/usr/include/semaphore.h中定义。

信号量的数据类型为结构sem_t,它本质上是一个长整型的数。函数sem_init()用来初始化一个信号量。它的原型为:

extern int sem_init __P ((sem_t *__sem, int __pshared, unsigned int __value));

sem为指向信号量结构的一个指针;pshared不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享;value给出了信号量的初始值。

函数sem_post( sem_t *sem )用来增加信号量的值。当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不在阻塞,选择机制同样是由线程的调度策略决定的。

函数sem_wait( sem_t *sem )被用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少。

函数sem_trywait ( sem_t *sem )是函数sem_wait()的非阻塞版本,它直接将信号量sem的值减一。

函数sem_destroy(sem_t *sem)用来释放信号量sem。

例1:使用信号量。例子中一共有4个线程,其中两个线程负责从文件读取数据到公共的缓冲区,另两个线程从缓冲区读取数据作不同的处理(加和乘运算)。

/* File sem.c */

#include

#include

#include

#define MAXSTACK 100

int stack[MAXSTACK][2];

int size=0;

sem_t sem;

/* 从文件1.dat读取数据,每读一次,信号量加一*/

void ReadData1(void){

FILE *fp=fopen("1.dat","r");

while(!feof(fp)){

fscanf(fp,"%d %d",&stack[size][0],&stack[size][1]);

sem_post(&sem);

++size;

}

fclose(fp);

}

/*从文件2.dat读取数据*/

void ReadData2(void){

FILE *fp=fopen("2.dat","r");

while(!feof(fp)){

fscanf(fp,"%d %d",&stack[size][0],&stack[size][1]);

sem_post(&sem);

++size;

}

fclose(fp);

}

/*阻塞等待缓冲区有数据,读取数据后,释放空间,继续等待*/ void HandleData1(void){

while(1){

sem_wait(&sem);

printf("Plus:%d+%d=%d\n",stack[size][0],stack[size][1],

stack[size][0]+stack[size][1]);

--size;

}

}

void HandleData2(void){

while(1){

sem_wait(&sem);

printf("Multiply:%d*%d=%d\n",stack[size][0],stack[size][1],

stack[size][0]*stack[size][1]);

--size;

}

}

int main(void){

pthread_t t1,t2,t3,t4;

sem_init(&sem,0,0);

pthread_create(&t1,NULL,(void *)HandleData1,NULL);

pthread_create(&t2,NULL,(void *)HandleData2,NULL);

pthread_create(&t3,NULL,(void *)ReadData1,NULL);

pthread_create(&t4,NULL,(void *)ReadData2,NULL);

/* 防止程序过早退出,让它在此无限期等待*/

pthread_join(t1,NULL);

}

在Linux下,用命令gcc -lpthread sem.c -o sem生成可执行文件sem。事先编辑好数据文件1.dat和2.dat,假设它们的内容分别为1 2 3 4 5 6 7 8 9 10和-1 -2 -3 -4 -5 -6 -7 -8 -9 -10 ,运行./sem,得到如下的结果:

Multiply:-1*-2=2

Plus:-1+-2=-3

Multiply:9*10=90

Plus:-9+-10=-19

Multiply:-7*-8=56

Plus:-5+-6=-11

Multiply:-3*-4=12

Plus:9+10=19

Plus:7+8=15

Plus:5+6=11

从中可以看出各个线程间的竞争关系。而数值并未按我们原先的顺序显示出来这是由于size这个数值被各个线程任意修改的缘故。这也往往是多线程编程要注意的问题

信号量和临界区

学习目标:

学习信号量及其属性

进行同步实验

研究临界区的行为

使用POSIX命名信号量和无名信号量

理解信号量的管理

1. 临界区

临界区是指必须以互斥的方式执行的代码段,也就是说临界区范围内只能由一个活动的线程。

例如:修改共享变量的过程中其他的执行线程可能会访问共享变量,那么修改共享变量的代码就被看成是临界区的一部分。

临界区问题指用安全、公平和对称的方式来执行临界区代码的问题

2. 信号量

信号量是(S)一个整型变量,它带有两个原子操作信号量锁定wait和信号量解锁signal。可以将其看成一个整数值和一个等待signal操作的进程列表。

wait操作:如果S大于零,wait就在一个原子操作中测试S,并对其进行减量运算;

如果S等于零,wait就在一个原子操作中测试S,并阻塞调用程序。signal操作:如果有线程在信号量上阻塞,S就等于零,signal就会解除对某个等待线程的阻塞;

如果没有线程在信号量上阻塞,signal就对S进行增量运算。信号量作用:

a:保护临界区

wait(&s)

signal(&s);

b:线程同步

process 1 executes: process 2 executes:

a; wait(&sync);

signal(&sync); b;

3. POSIX:SEM无名信号量

信号量是一个sem_t类型的变量,有相关的原子操作来对它的值进行初始化、增量和减量操作。如果一个实现在unistd.h中定义了_POSIX_SEMAPHORES,那么这个实现就支持POSIX:SEM信号量。无名信号量和命名信号量之间的区别类似于普通管道和命名管道之间的区别

信号量的申明:

#include

sem_t sem;

信号量的初始化:必须在使用信号量之前对其进行初始化

#include

int sem_init(sem_t *sem, int pshared, unsigned value);

没有规定成功时返回值,不成功返回-1并设置errno,必须检测的错误码:

EINV AL value大于SEM_V ALUE_MAX

ENOSPC 初始化资源已经耗尽,或者信号量的数目超出了SEM_NSEMS_MAX的范围

EPERM 调用程序不具有适当的特权

参数pshared等于0,说明信号量只能由初始化这个信号量的进程中的线程使用;

如果pshared非零,任何可以访问sem的进程都可以使用这个信号量。

注:在创建信号量之后创建一个子进程,并没有提供对信号量的访问,子进程收到的是信号量的拷贝,而不是真的信号量。

例:创建一个有进程中的线程使用的信号量

sem_t semA;

if (sem_init(&semA, 0, 1) == -1 )

{

perror (“failed to initialize semaphore semA”);

}

信号量的销毁:

#include

int sem_destroy(sem_t *sem);

成功返回0,不成功返回-1并设置errno,检测错误码:

EINV AL sem不是有效的信号量

例:

if (sem_destroy(&semA) == -1)

{

perror (“Failed to destroy semA”);

}

POSIX申明:销毁一个已经销毁的信号量的结果是未定义的。有其他线程阻塞在一个信号量上时,销毁这个信号量的结果也是未定义的。

4. POSIX:SEM信号量的操作

这里描述的信号量的操作适用与无名信号量,同时也适用命名信号量

signal操作:

#include

int sem_post(sem_t *sem);

成功返回0,不成功返回-1并设置errno,必须检测的错误码:

EINV AL *sem不对应有效的信号量

函数sem_init是信号安全的,可以在信号处理程序中调用它。

wait操作:

#include

int sem_trywait(sem_t *sem);

int sem_wait(sem_t *sem);

成功返回0,不臣工返回-1并设置errno,必须检测的错误码

EINV AL *sem不对应有效的信号量

EAGAIN 函数sem_trywait不会阻塞,而是设置errno后返回

EINTR 被信号中断

如果信号量为0,则调用进程一直阻塞直到一个相应的sem_post调用解除了对它的阻塞为止,或者直到它被信号中断为止(被信号中断后必须手动重启)。

#include

#include

static int shared = 0;

static sem_t sharedsem;

int initshared(int val)

{

if (sem_init(&sharedsem, 0, 1) == -1)

{

return -1;

}

shared = val;

return 0;

}

int getshared(int *val)

{

while (sem_wait(&sharedsem) == -1) //必须考虑被信号中断,重启的情况

{

if (errno != EINTR)

return -1;

}

*val = shared;

return sem_post(&sharedsem); //信号安全的,无须考虑

}

int incshared()

{

while (sem_wait(&sharedsem) == -1)

{

if (errno != EINTR)

return -1;

}

shared++;

return sem_post(&sharedsem);

}

注:如果既要在main程序中,又要在信号处理程序中对一个变量进行增量操作,如何用上面的程序保护着个变量?

如果不做一些其他的操作,使不能用它来保护这个变量的。如果信号是在上面程序中的某个函数调用锁定了信号量的时候被捕捉到的,那么在信号处理程序中对这些函数中的某一个进行调用的时候,就会引起死锁。

正确的做法是在调用getshared和incshared之前将信号阻塞,调用完成后,解除信号阻塞。

例:创建一个信号量,并将其传递给多个线程,线程函数调用信号量保护临界区

#include

#include

#include

#include

#include

#include

#include

#define TEN_MILLION 10000000L

#define BUFSIZE 1024

void *threadout(void *args)

{

char buffer[BUFSIZE];

char *c;

sem_t *semlockp;

struct timespec sleeptime;

semlockp = (sem_t *)args;

https://www.doczj.com/doc/a716885725.html,_sec = 0;

https://www.doczj.com/doc/a716885725.html,_nsec = TEN_MILLION;

snprintf (buffer, BUFSIZE, "This is a thread from process %ld\n",

(long)getpid());

c = buffer;

//临界区入口

while (sem_wait(semlockp) == -1)

{

if (errno != EINTR)

{

fprintf (stderr, "Thread failed to lock semaphore\n");

return NULL;

}

}

//临界区

while (*c != '\0')

{

fputc (*c, stderr);

c++;

nanosleep(&sleeptime, NULL); //非忙等循环

}

//临界区出口

if (sem_post(semlockp) == -1)

{

fprintf (stderr, "Thread failed to unlock semaphore\n");

}

return NULL;

}

int main(int argc, char *argv[])

{

int error;

int i;

int n;

sem_t semlock;

pthread_t *tids;

if (argc != 2)

{

fprintf (stderr, "Usage: %s numthreads\n", argv[0]);

return 1;

}

n = atoi (argv[1]);

tids = (pthread_t *)calloc(n, sizeof(pthread_t));

if (tids == NULL)

{

perror ("Failed to initialize semaphore");

return 1;

}

if (sem_init(&semlock, 0, 1) == -1)

{

perror ("Failed to initialize semaphore");

return 1;

}

for (i=0; i

{

error = pthread_create(tids+i, NULL, threadout, (void *)&semlock);

if (error != 0)

{

fprintf (stderr, "Failed to create thread:%s\n", strerror(error));

return 1;

}

}

for (i=0; i

{

error = pthread_join(tids[i], NULL);

if (error != 0)

{

fprintf (stderr, "Failed to join thread:%s\n", strerror(error));

return 1;

}

}

return 0;

}

注:sem_init(&semlock, 0, 1) 将semlock初始化为1,如果0的话将产生死锁。stderr 标准输出是排他性资源,同时只能由一个线程使用。

如果改称sem_init(&semlock, 0, 2),程序输出将会混乱。

检测命名信号量和无名信号量的值:

#include

int sem_getvalue(sem_t *restrict sem, int *restrict sval);

成功返回0,不成功返回-1并设置errno,必须检测错误码:

EINV AL *sem不对应一个有效的信号量

函数可以用来检测一个命名信号量或者无名信号量的值。

5. POSIX:SEM命名信号量

命名信号量用来同步那些不共享内存的进程。

命名信号量和文件一样,有一格名字、有一个用户ID、一个组ID和权限。

如果两个进程(线程)打开的信号量一“/”开头,则其引用同一个信号量。

因此,通常都要为POSIX:SEM命名信号量使用以“/”开头的名字。

5.1创建并打开命名信号量

#include

sem_t *sem_open( const char *name, int oflag, ...);

成功返回信号量的地址,不成功返回SEM_FAILED并设置errno,必须检测的错误码:EACCES 权限不够

EEXIST 设置了O_CREATE和O_EXCL,而且信号量存在

EINTR 函数别信号中断

EINV AL name不能作为信号量打开、或者试图用大于SEM_V ALUE_MAX的值创建信号量

EMFILE 进程使用了太多的文件描述符或信号量

ENAMETOOLONG name比PATH_MAX长、或者它有一个组件超出NAME_MAX 范围

ENFILE 系统中打开了太多的信号量

ENOENT 没有设置O_CREA TE,而且信号量也不存在

ENOSPC 没有足够的空间了创建信号量

函数sem_open功能说明:

参数oflag用来确定是创建信号量,还是仅仅由函数对其进行访问。

如果参数oflag设置了O_CREATE比特位就必须设置mode位(mode_t类型的权限位)和value位(unsigned类型的信号量初始值)。

如果O_CREATE和O_EXCL位都设置了,那么信号量已经存在的话,函数返回一个错误。

如果仅仅设置了O_CREATE位,那么信号量如果存在,信号量会忽略O_CREATE和其他额外的参数

在信号量已经存在的情况下,POSIX没有提供直接设置命名信号量值得方法

例:访问一个命名信号量,如果不存在就创建它

#include

#include

#include

#include

#include

#include

#include

#include

#define PERMS (mode_t)(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

#define FLAGS (O_CREAT | O_EXCL)

#define BUFSIZE 1024

int getnamed(char *name, sem_t **sem, int val)

{

while ( ((*sem = sem_open(name, FLAGS, PERMS, val)) == SEM_FAILED) && (errno == EINTR)); //创建命名信号量,遇信号中断重启

if (*sem != SEM_FAILED) //创建成功返回

return 0;

if (errno != EEXIST) //失败返回,已经存在执行读取

return -1;

//信号量已经存在,读取它

while ( ((*sem = sem_open(name, 0)) == SEM_FAILED) && (errno == EINTR));

if (*sem != SEM_FAILED)

return 0;

return -1;

}

int main(int argc, char *argv[])

{

char buffer[BUFSIZE];

char *c;

pid_t childpid = 0;

int delay;

volatile int dummy = 0;

int i;

int n;

sem_t *sem_lockp;

if (argc != 4)

{

fprintf (stderr, "Usage: %s processes delay semaphorename\n", argv[0]);

return 1;

}

n = atoi(argv[1]);

delay = atoi(argv[2]);

for (i=1; i

{

if (childpid = fork())

break; //重要,不能少,子进程推出循环,父进程继续执行循环

}

snprintf (buffer, BUFSIZE, "i:%d process ID:%ld parent ID:%ld child ID:%ld\n",

i, (long)getpid(), (long)getppid(), (long)childpid);

c = buffer;

if (getnamed(argv[3], &sem_lockp, 1) == -1)

{

perror ("Failed to create named semaphore");

return 1;

}

while (sem_wait(sem_lockp) == -1) //进入临界区

{

if (errno != EINTR)

{

perror("Failed to lock semlock");

return 1;

}

}

while (*c != '\0') //临界区

{

fputc (*c, stderr);

c++;

for (i=0; i

dummy++;

}

if (sem_post(sem_lockp) == -1) //退出临界区

{

perror("Failed to unlock semlock");

return 1;

}

if (wait(NULL) == -1) //等待子进程结束返回

return 1;

return 0;

}

注1:命名信号量就像文件一样存在系统中的。如果同时运行两个以上程序在一台机器上,则还能够正常运新

注2:如果上面的程序正在运行,输入Ctrl-C退出,然后再次运行它,又可能进程都会阻塞,因为Ctrl-C产生的信号有可能在信号量的值为0时被传递。下次运行程序时,信号量的初始值是0,所以所有的进程阻塞。

命名信号量使多个进程可以实现同步和互斥,无名信号量使同一个进程的多个线程实现同步和互斥。

5.2关闭并删除命名信号量

与命名管道一样,命名信号量在单个程序的执行之外是具有持久性的。

关闭信号量:

#include

int sem_close(sem_t *sem);

成功返回0,不成功返回-1并设置errno,检测错误码:

EINV AL *sem不是一个有效的信号量

删除命名信号量:

#include

int sem_unlink(const char *name);

成功返回0,不成功返回-1并设置errno,检测错误码:

EACCES 权限不正确

ENAMETOOLONG name比PATH_MAX长、或者它有一个组件超出NAME_MAX 范围

ENOENT 信号量不存在

说明1:函数在素有的进程关闭了命名信号量之后将命名信号量从系统中删除。当进程显示地调用SEM_CLOSE、_exit、exit、exec或执行从main的返回式,就会出现关闭操作。

说民2:sem_unlink之后,即使其他的进程仍然将老的信号量打开着,用相同的名字调用的sem_open引用的也是新的信号量。即使其他的进程将信号量打开着,sem_unlink 函数也总是会立即返回。

例:关闭并删除命名信号量的函数

#include

#include

int destroynamed(char *name, sem_t *sem)

{

int error = 0;

if (sem_close(sem) == -1)

error = errno;

if ( (sem_unlink(name) != -1) && !error)

return 0;

if (error != 0)

errno = error;

return -1;

}

注:命名信号量具有持久性的。如果创建了这样的一个信号量,即使创建它的进程和

所有可以访问它的进程都终止了,它还是一直存在于系统中,保持它的值直到被销毁为止。

POSIX没有提供方法来确定那些命名信号量是存在的。当显示目录内容是,他们又可能会出现,也有可能不出现。当系统重启时,他们有可能被销毁,也可能不被销毁。

第3章部分习题测验答案

第3章部分习题答案 3.2. 为什么进程在进入临界区之前,应先执行"进入区"代码,在退出临界区后又执行"退出区"代码? 为了实现多个进程对临界资源的互斥访问,必须在临界区前面增加一段用于检查欲访问的临界资源是否正被访问的代码,如果未被访问,该进程便可进入临界区对资源进行访问,并设置正被访问标志,如果正被访问,则本进程不能进入临界区,实现这一功能的代码成为"进入区"代码;在退出临界区后,必须执行"退出区"代码,用于恢复未被访问标志. 3.3 同步机构应遵循哪些基本准则?为什么? a. 空闲让进. b. 忙则等待. c. 有限等待. d. 让权等待. 3.6你认为整型信号量机制和记录型信号量机制,是否完全遵循了同步机构的四条准则? a. 在整型信号量机制中,未遵循"让权等待"的准则. b. 记录型信号量机制完全遵循了同步机构的"空闲让进,忙则等待,有限等待,让权等待"四条准则. 3.9在生产者-消费者问题中,如果缺少了signal(full)或signal(empty),对执行结果会有何影响? 生产者-消费者问题可描述如下: var mutex,empty,full: semaphore:=1,n,0; buffer: array[0,...,n-1] of item; in,out: integer:=0,0; begin parbegin producer: begin repeat . . produce an item in nextp; . . wait(empty); wait(mutex); buffer(in):=nextp; in:=(in+1) mod n; signal(mutex); /* ************** */ signal(full); /* ************** */ until false; end consumer: begin repeat wait(full); wait(mutex); nextc:=buffer(out); out:=(out+1) mod n; signal(mutex); /* ************** */

机制习题解答(DOC)

第1章习题及解答略 第2&6章习题及解答 1.判断正误 (1)凡频谱是离散的信号必然是周期信号。( ×)准周期信号 (2)任何周期信号都由频率不同,但成整倍数比的离散的谐波叠加而成。( ×) (3)周期信号的频谱是离散的,非周期信号的频谱也是离散的。( ×) (4)周期单位脉冲序列的频谱仍为周期单位脉冲序列。( √) (5)非周期变化的信号就是随机信号。( ×)准周期信号 (6)非周期信号的幅值谱表示的是其幅值谱密度与时间的函数关系。( ×) (7)信号在时域上波形有所变化,必然引起频谱的相应变化。( ×) (8)各态历经随机过程是平稳随机过程。( √) (9)平稳随机过程的时间平均统计特征等于该过程的集合平均统计特征。( √) (10)非周期信号的频谱都是连续的。( ×) 准周期信号 (11)单位脉冲信号的频谱是无限带宽谱(√) (12)直流信号的频谱是冲击谱(√) 2.选择正确答案填空 (1)描述周期信号的数学工具是(B )。 A.相关函数 B. 傅里叶级数 C. 拉普拉斯变换 D. 傅里叶变换 (2)描述非周期信号的数学工具是( C)。 A.三角函数 B. 拉普拉斯变换 C. 傅里叶变换 D. 傅里叶级数

(3) 将时域信号进行时移,则频域信号将会( D ) A.扩展 B. 压缩 C. 不变 D. 仅有相移 (4) 瞬变信号的傅里叶变换的模的平方的意义为( C ) A.信号的一个频率分量的能量 B. 在f 处的微笑频宽内,频率分量的能量与频宽之比 C. 在f 处单位频宽中所具有的功率 (5) 概率密度函数是在(C )域,相关函数是在(A )域,功率谱密度函数是 在( D )域描述随机信号。 A.时间 B. 空间 C. 幅值 D. 频率 (6) 白噪声信号的自相关函数是(C ) A.相关函数 B. 奇函数 C. 偶函数 D. 不存在 6.4已知被测模拟量最大输出幅值为±5V ,要求AD 转换输出最大误差不大于5mv ,应选用多少位的AD 转换器? 解:量化误差5mv=±0.5LSB=125*5.012* 5.0-±=-±n n V FS 解得n=9 6.6 模拟信号DFT ,请问采样时间间隔Δt 、采样点数N 、频率分辨率Δf 三者之间的关系?并回答如下问题: (1) 为什么采样频率Δf 必须至少为被分析信号中最高频率成分的2倍才能避免混淆? (2) 当采样频率确定后,频谱中应该出现的最高频率是多少? (3) 频谱中的谱线根数是否与时域中的采样点数相同?对于频谱分析来说有用的谱线根数是多少?

实验四 Linux进程互斥

实验四 Linux进程互斥 一、实验目的 熟悉Linux下信号量机制,能够使用信号量实现在并发进程间的互斥和同步。 二、实验题目 使用共享存储区机制,使多个并发进程分别模拟生产者-消费者模式同步关系、临界资源的互斥访问关系,使用信号量机制实现相应的同步和互斥。 三、背景材料 (一)需要用到的系统调用 实验可能需要用到的主要系统调用和库函数在下面列出,详细的使用方法说明通过“man 2 系统调用名”或者“man 3 函数名”命令获取。 fork() 创建一个子进程,通过返回值区分是在父进程还是子进程中执行; wait() 等待子进程执行完成; shmget() 建立一个共享存储区; shmctl() 操纵一个共享存储区; s hmat() 把一个共享存储区附接到进程内存空间; shmdt() 把一个已经附接的共享存储区从进程内存空间断开; semget() 建立一个信号量集; semctl() 操纵一个信号量集,包括赋初值; semop() 对信号量集进行wait和signal操作; signal() 设置对信号的处理方式或处理过程。 (二)模拟生产者-消费者的示例程序 本示例主要体现进程间的直接制约关系,由于使用共享存储区,也存在间接制约关系。进程分为服务进程和客户进程,服务进程只有一个,作为消费者,在每次客户进程改变共享存储区内容时显示其数值。各客户进程作为生产者,如果共享存储区内容已经显示(被消费),可以接收用户从键盘输入的整数,放在共享存储区。 编译后执行,第一个进程实例将作为服务进程,提示: ACT CONSUMER!!! To end, try Ctrl+C or use kill. 服务进程一直循环执行,直到用户按Ctrl+C终止执行,或使用kill命令杀死服务进程。 其他进程实例作为客户进程,提示: Act as producer. To end, input 0 when prompted. 客户进程一直循环执行,直到用户输入0。 示例程序代码如下: #include #include #include #include #include #include #include #include

计算机操作系统典型例题解析之三

计算机操作系统典型例题解析之三 【例1】分配到必要的资源并获得处理机时的进程状态是(B )。A、就绪状态B、执行状态 C、阻塞状态D、新状态 分析:进程有三种基本状态:就绪状态、执行状态和阻塞状态。当进程已分配到除CPU以外的所有必要的资源后,只要能再获得处理机便可立即执行,这时的状态称为就绪状态;处于就绪状态的进程如果获得了处理机,其状态转换为执行状态;进程因发生某种事件(如I/O请求、申请缓冲空间等)而暂停执行时的状态,亦即进程的执行受到阻塞,故称这种状态为阻塞状态;而新状态是指创建了进程但尚未把它插入到就绪队列前的状态。所以本题的答案是B。 【例2】挂起的进程被激活,应该使用(C)原语。 A、Create B、Suspend C、Active D、Wakeup 分析:在不少系统中,进程除了三种基本状态外,又增加了一些新的状态,其中最重要的是挂起状态。“挂起”的实质是使进程不能继续执行,即使挂起后的进程处于就绪状态,它也不能参加对CPU的竞争,进程的挂起调用Suspend()原语。因此,被挂起的进程处于静止状态,相反,没有挂起的进程则处于活动状态。而且,处于静止状态的进程,只有通过“激活”动作,调用Active()原语,才能转换成活动状态,调入内存。所以本题的答案是C。 【例3】任何时刻总是让具有最高优先数的进程占用处理器,此时采用的进程调度算法是(D)。A非抢占式的优先数调度算法B、时间片轮转调度算法C、先来先服务调度算法D、抢占式的优先

数调度算法 分析:“让具有最高优先数的进程占用处理器”,我们可以知道,采用的进程调度算法是优先数调度算法,但是我们还要进一步分析是抢占式的还是非抢占式的。“任何时刻总让”,通过这句话我们知道采用的是抢占式的,所以本题的答案是D。 【例4】若P、V操作的信号量S初值为2,当前值为-1,则表示有(B)等待进程。A、0个B、1个C、2个D、3个分析:信号量的初始值表示系统中资源的数目,每次的Wait操作意味着进程请求一个单位的资源,信号量进行减1的操作,当信号量小于0时,表示资源已分配完毕,进程自我阻塞。因此,如果信号量小于0,那么信号量的绝对值就代表当前阻塞进程的个数。所以本题的答案是B。 【例5】发生死锁的必要条件有四个,要预防死锁的发生,可以破坏这四个必要条件,但破坏(A)条件是不太实际的。 A、互斥 B、请求和保 C、不剥夺 D、环路等待 分析:预防死锁是指通过破坏死锁的某个必要条件来防止死锁的发生。四个必要条件中,后三个条件都可以被破坏,而第一个条件,即“互斥”条件,对某些像打印机这样的设备,可通过SPOOLing技术予以破坏,但其他资源,因受它们的固有特性的限制,该条件不仅不能被破坏,反而应加以保证。所以本题的答案是A。 【例6】有m个进程共享同一临界资源,若使用信号量机制实现对临界资源的互斥访问,则信号量值的变化范围是1 至1-m。

Linux-期末考试试题8套(含答案)

Linux 期末考试试题(一) 一、选择题 (每小题2分,共50分) 1.在创建Linux分区时,一定要创建(D )两个分区 A. FAT/NTFS B. FAT/SWAP C. NTFS/SWAP D.SW AP/根分区 2.在Red Hat Linux 9中,系统默认的(A)用户对整个系统拥有完全的控制权。 A. root B. guest C. administrator D.supervistor. 3. 当登录Linux时,一个具有唯一进程ID号的shell将被调用,这个ID是什么( B ) A. NID B. PID C. UID D. CID 4. 下面哪个命令是用来定义shell的全局变量( D ) A. exportfs B. alias C. exports D. export 5. 哪个目录存放用户密码信息( B ) A. /boot B. /etc C. /var D. /dev 6. 默认情况下管理员创建了一个用户,就会在( B )目录下创建一个用户主目录。 A. /usr B. /home C. /root D. /etc 7. . 当使用mount进行设备或者文件系统挂载的时候,需要用到的设备名称位于( D )目录。 A. /home B. /bin C. /etc D. /dev 8. 如果要列出一个目录下的所有文件需要使用命令行( C )。 A. ls –l B. ls C. ls –a(所有) D. ls –d 9. 哪个命令可以将普通用户转换成超级用户(D ) A. super B. passwd C. tar D. su 10. 除非特别指定,cp假定要拷贝的文件在下面哪个目录下( D ) A. 用户目录 B. home目录 C. root目录 D. 当前目录 11. 在vi编辑器里,命令"dd"用来删除当前的( A ) A. 行 B. 变量 C. 字 D. 字符 12. 当运行在多用户模式下时,用Ctrl+ALT+F*可以切换多少虚拟用户终端( B ) A. 3 B. 6 C. 1 D. 12 13. Linux启动的第一个进程init启动的第一个脚本程序是( B )。 A./etc/rc.d/init.d B./etc/rc.d/rc.sysinit C./etc/rc.d/rc5.d D./etc/rc.d/rc3.d 14. 按下(A )键能终止当前运行的命令 A. Ctrl-C B. Ctrl-F C. Ctrl-B D. Ctrl-D 15. 下面哪个命令用来启动X Window ( C ) A. runx B. Startx C. startX D. xwin 16. 用来分离目录名和文件名的字符是( B ) A. dash (-) B. slash (/) C. period (.) D. asterisk(*) 17. 用"rm -i",系统会提示什么来让你确认( B ) A. 命令行的每个选项 B. 是否真的删除 C. 是否有写的权限 D. 文件的位置 18. 以下哪个命令可以终止一个用户的所有进程( D ) A. skillall B. skill C. kill D. killall 19.在Red Hat Linux 9中,一般用(D )命令来查看网络接口的状态 A. ping B. ipconfig C. winipcfg D ifconfig 20. vi中哪条命令是不保存强制退出( C )(第五章) A. :wq B. :wq! C. :q! D. :quit 21.局域网的网络设备通常有(ABCDE)

基于Linux的信号量通信机制研究与实现

系统软件与软件工程本栏目责任编辑:谢媛媛Computer Knowledge and Technology 电脑知识与技术第6卷第12期(2010年4月)基于Linux 的信号量通信机制研究与实现 袁玉锦,周群 (邯郸学院网络中心,河北邯郸056005) 摘要:该文以信号量通信理论为基础,通过对Linux 信号量相关系统调用的分析,着重讨论了内核级和用户级的信号量通信、同一进程内线程之间的通信、多用户的进程间的通信等问题,并采用ANSI C 编写了信号量通信的具体实例。 关键词:信号量;Linux ;多进程通信;线程通信 中图分类号:TP316文献标识码:A 文章编号:1009-3044(2010)12-3279-03 1信号量通信理论 操作系统原理中利用信号量来解决多进程互斥访问临界资源的问题,还可来描述多进程之间的前趋关系,即同步问题。 信号量的概念由荷兰学者E.W.Dijkstra 于1965年提出。信号量实际是一个整数,进程(也可以是线程)在信号量上的操作分2种,一种称为P 操作,另一种称为V 操作。P 操作是让信号量的值减1,V 操作是让信号量的值加1。在进行实际的操作之前,进程首先检查信号量的当前值,如果当前值大于0,则可以执行P 操作,否则进程休眠,等待其他进程在该信号量上的V 操作,因为其他进程的V 操作将让信号量的值增加,从而它的P 操作可以成功完成。某信号量在经过某个进程的成功操作之后,其他休眠在该信号量上的进程就有可能成功完成自己的操作,这时系统负责检查休眠进程是否可以完成自己的操作。 在操作系统中,信号量最简单的形式也是最初被提出时定义的形式是一个整数,多个进程可检查并设置信号量的值。这种检查并设置(Test-and-Set)操作是不可中断的,也称为“原子”操作。检查并设置操作的结果是信号量的当前值和设置值相加的结果,该设置值可以是正值,也可以是负值。根据检查并设置操作的结果,进行操作的进程可能会进入休眠状态,而当其他进程完成自己的检查并设置操作后,由系统检查前一个休眠进程是否可以在新信号量值的条件下完成相应的检查并设置操作。这样,通过信号量,就可以协调多个进程的操作,实现多进程之间通信。 操作系统原理中通常把信号、信号量通信称为低级通信,而把管道、消息队列、共享存储区通信称为高级通信。信号量分为有名、无名两种,进程间通信用有名信号量,同一进程内部通信一般用无名信号量。 2Linux 中的信号量 从意义和实现机理上,Unix System V 或Linux 的信号量与以上所述的常规信号量没有什么区别,但System V 提供的信号量机制要复杂得多,并且分为两种不同系统调用类型:一种是用内核级的信号量,有关系统调用在/usr/include/semaphore.h 中包含,一般可用于内核级的进程通信和内核级的线程通信;另一种是用户级信号量,有关系统调用在/usr/include/sys/sem.h 中包含,一般可用于多用户进程之间通信。 2.1内核级的信号量相关系统调用 int sem_init (sem_t *sem ,int pshared ,unsigned int value) 作用:为单个信号量设置初值,第一参数*sem 为指定的信号量对象;第二参数pshared 为共享标志,如值为0表示私有信号量,非0表示可以与其他进程共享的信号量;第三参数value 为要为信号量设置的初值。 相关数据结构如下: struct{struct{long int status ; int spin_lock ;}sem_lock ; int sem_value ; pthread_descr sem_waiting ; }sem_t int sem_wait (sem_t *sem); 作用:对指定的信号量进行P 操作。 Int sem_post (sem_t *sem); 作用:对指定的信号量进行V 操作。 总结:以上是内核级信号量通信常用到的三个系统调用,使用方式较为简单,但主要适用于内核级多线程之间通信,后面将给出多线程通信的具体实例。 收稿日期:2010-02-21 作者简介:袁玉锦(1980-),女,河北曲周人,邯郸学院网络中心,助教,学士,研究方向为计算机网络;周群(1981-),女,河北武安 人,助教,学士,主要研究方向为计算机网络。 ISSN 1009-3044Computer Knowledge and Technology 电脑知识与技术Vol.6,No.12,April 2010,pp.3279-3281E-mail:xsjl@https://www.doczj.com/doc/a716885725.html, https://www.doczj.com/doc/a716885725.html, Tel:+86-551-569096356909643279

linux题库选择及答案

一、选择题 1.在创建Linux分区时,一定要创建(D )两个分区 A. FAT/NTFS B. FAT/SWAP C. NTFS/SWAP D.SW AP/根分区 2.在Red Hat Linux中,系统默认的(A)用户对整个系统拥有完全的控制权。 A. root B. guest C. administrator D.supervistor. 3. 当登录Linux时,一个具有唯一进程ID号的shell将被调用,这个ID是什么( B ) A. NID B. PID C. UID D. CID 4. 下面哪个命令是用来定义shell的全局变量( D ) A. exportfs B. alias C. exports D. export 5. 哪个目录存放用户密码信息( B ) A. /boot B. /etc C. /var D. /dev 6. 默认情况下管理员创建了一个用户,就会在( B )目录下创建一个用户主目录。 A. /usr B. /home C. /root D. /etc 7. . 当使用mount进行设备或者文件系统挂载的时候,需要用到的设备名称位于( D )目录。 A. /home B. /bin C. /etc D. /dev 8. 如果要列出一个目录下的所有文件需要使用命令行( C )。 A. ls –l B. ls C. ls –a(所有) D. ls –d 9. 哪个命令可以将普通用户转换成超级用户(D ) A. super B. passwd C. tar D. su 10. 除非特别指定,cp假定要拷贝的文件在下面哪个目录下( D ) A. 用户目录 B. home目录 C. root目录 D. 当前目录 11. 在vi编辑器里,命令"dd"用来删除当前的( A ) A. 行 B. 变量 C. 字 D. 字符 12. 当运行在多用户模式下时,用Ctrl+ALT+F*可以切换多少虚拟用户终端( B ) A. 3 B. 6 C. 1 D. 12 13. Linux启动的第一个进程init启动的第一个脚本程序是( B )。 A./etc/rc.d/init.d B./etc/rc.d/rc.sysinit C./etc/rc.d/rc5.d D./etc/rc.d/rc3.d 14. 按下(A )键能终止当前运行的命令 A. Ctrl-C B. Ctrl-F C. Ctrl-B D. Ctrl-D 15. 下面哪个命令用来启动X Window ( C ) A. runx B. Startx C. startX D. xwin 16. 用来分离目录名和文件名的字符是( B ) A. dash (-) B. slash (/) C. period (.) D. asterisk(*) 17. 用"rm -i",系统会提示什么来让你确认( B ) A. 命令行的每个选项 B. 是否真的删除 C. 是否有写的权限 D. 文件的位置 18. 以下哪个命令可以终止一个用户的所有进程( D ) A. skillall B. skill C. kill D. killall 19.在Red Hat Linux 9中,一般用(D )命令来查看网络接口的状态 A. ping B. ipconfig C. winipcfg D ifconfig 20. vi中哪条命令是不保存强制退出( C )(第五章) A. :wq B. :wq! C. :q! D. :quit 21.局域网的网络设备通常有(ABCDE)

信号量互斥题目

试用用信号量机制描述两人下象棋的过程。 两人下象棋的过程可以概括为:一开始只能是“红先黑后”,以后两人要循环轮流走子,直至某一方获胜或双方和棋为

止。? 这是个只有一个生产者和一个消费者的生产者——消费者问题,是个典型的“你等我,我也等你”的问题。红方是总的前趋任务——生产者进程,黑方是总的后继任务——消费者进程,但由于下棋过程必须轮流走子,所以红黑双方的生产者消费者身份会轮流改变。棋盘则是生产者与消费者共享的缓冲。?要求:只描述对弈过程,对棋盘的访问不做描述。二人对弈过程是个纯粹的同步过程 ①所用信号量设臵如下: Ⅰ)同步信号量hei,初值为1,表示黑方已走子,开始时可使红方先行不受阻。 Ⅱ)同步信号量hong,初值为0,表示红方尚未走子,开始时可使黑方先行受阻。 用信号量机制描述的二人下象棋过程如下

有一个阅览室,共有100个座位,读者进入时必须先在一张登记表上登记,该表为每一座位列一表目,包括座号和读者姓名等,读者离开时要消掉登记的信息,试问: (1)为描述读者的动作,应编写几个程序,设臵几个进程?(2)试用P、V操作描述读者进程之间的同步关系。分析:?读者的动作都是一样的:登记进入阅览室,阅读, 撤消登记离开阅览室,因此可写一个程序,设n个进程。 ?读者共享的资源有阅览室的座位和登记表,因此诸 个读者进程之间有两种互斥制约关系,需设2个信号量来实现:? seat:用于实现诸读者对阅览室的空闲座位的互斥 竞争,初值为100; ? mutex:用于实现诸读者对登记表的互斥访问,初值 为1

(1)可写一个程序,设n个进程 (2)读者进程readeri(i=1,2,3,……)描述如下: P(seat); /*申请空座位*/ P(mutex); /*申请登记*/ 登记; V(mutex) /*允许其他读者登记*/ 阅读; P(mutex); /*申请撤消登记*/ 撤消登记; V(mutex); /*允许其他读者撤消登记*/ V(seat); /*释放座位,允许他人进入*/

信号量,中断和时间

第6章信号量,中断和时间 信号量(Signal)是进程间通讯(IPC)的一种形式——是一个进程给另一个进程发送信息的方法。但是信息不可能很多——一个信号量不可能携带详细的信息,即使是传送者的身份也不能被传递;唯一能够确定的事实是信号量的确被发送了。(然而和经典信号量不同,POSIX实时信号量允许传送稍微多一点的信息。)实际上,信号量对于双向通讯是没有用处的。还有,根据某些限定,信号量的接受者不必以任何方式作出响应,甚至可以直接忽略大部分信号量。 虽然有这么多的限制,然而信号量仍然是一种功能强大的十分有用的机制——勿庸置疑,这是Unix IPC中使用最频繁的机制。每当进程退出或者废弃一个空指针时,每当使用Ctrl+C键终止程序运行时,都要传递信号量。 第9章会更详细的讨论IPC机制。对于本章的讨论来说,信号量的内容就足够讨论了。 正如在Linux内核本身的代码注释中所说明的一样,中断(Interrupt)对于内核来说和信号量是类似的。中断一般都是从磁盘之类的硬件设备送往内核,用以提示内核该设备需要加以注意。一个重要的硬件中断源就是定时器设备,它周期性地通知内核已经通过的时间。如同第5章中阐述的一样,中断也可以由用户进程通过软件产生。 在本章中,我们首先讨论一下Linux中信号量和中断的实现,最后再浏览一下Linux的时间处理方式。 虽然内核对代码的要求标准非常严格,本章所涉及的代码仍然特别清晰明白。本章使用的一般方法是首先介绍相关的数据结构和它们之间的关系,接下来讨论操纵和查询它们的函数。 锁的概述 锁的基本思想是限制对共享资源的访问——共享资源包括共享的文件,共享的内存片,以及在一次只能由一个CPU执行的代码段。概括的说,在单处理器上运行的Linux内核并不需要锁,这是因为在编写Linux内核时就已经注意到要尽量避免各种可能需要锁的情况了。但是,在多处理器机器上,一个处理器有时需要防止其它处理器对它的有害的介入。 include/asm-i386/spinlock.h文件(从12582行开始)并不使用难看的#ifdef把所有对锁函数的调用封装起来,它包含一系列对单处理器平台(UP)基本为空的宏,然而在多处理器平台(SMP)上这些宏将展开成为实际代码。因而内核的其它代码对UP和SMP(当涉及到这种特性时)都是相同的,但是它们两个的效果却是迥然不同的。 第10章中涉及SMP的部分会对锁做深入的介绍。但是,由于你在代码中将到处都能够看到对锁宏的调用,特别是在本章所讨论到的代码中这一点尤为明显,所以你应该首先对宏的用途有初步了解——以及为什么现在在大多数情况下我们都可以安全地将其忽略(我们将在讨论的过程中对其中的异常情况进行说明)。 信号量 Linux内核将信号量分为两类: 非实时的(Nonrealtime)——大部分是些传统的信号量,例如SIGSEGV,SIGHUP

计算机操作系统算法题(最全)

6. 算法题(共32个题目) 200348. 在信号量机制中,若P(S)操作是可中断的,则会有什么问题? 此题答案为:答: P(S)的操作如下: Begin S.Value:= S.Value-1; ① If S.Value<0 Then ② Begin Insert(*,S.L); Block(*) ③ End End. 若P(S)可中断的,例如进程A在执行了语句①之后从CPU上退 下了,假定此时S.Value=0;这时换另一进程B,B又将S.Value 的值减1使之为-1,在执行语句③时,B被阻塞;然后又换回A执行,由于A的"断点"是语句①之后,当它执行语句②时,由于这时S.Value已经是-1,故进程继续执行而被阻塞。这就出现了错误: 本来A操作P(S)操作后,S.Value=0,是不应该被阻塞的,现在却被阻塞了。 200350. 何谓临界区?下面给出的两个进程互斥的算法是安全的吗?为什么?

#define true; # define false; Int flag[2]; flag[1]=flag[2]=false; enter-crtsec(i) int i; { While(flag[1-i]) flag[i]=true; } feave-crtsec(i) Int i; { flag[i]=false; } process I; … Enter-crtsec(i); In critical section; Leave-crtsec(i);

此题答案为:答:一次仅允许一个进程使用的资源称为临界资源,在进程中对临界资源访问的程序段称为临界区。 从概念上讲,系统中各进程在逻辑上是独立的,它们可以按各自的速度向前推进。但由于它们共享某些临界资源,因而产生了临界区问题。对于具有临界区问题的并发进程,它们之间必须互斥,以保证不会同时进入临界区。 这种算法不是安全的。因为,在进入临界区的enter-crtsec()不是一个原语操作,如果两个进程同时执行完其循环(此前两个flag均为false),则这两个进程可同时进入临界区。 200353. 某车站售票厅,任何时刻最多可容纳20名购票者进入,当售票少于20名购票者时,则厅外的购票者可立即进入,否则需在外面等待。若把一个购票者看作一个进程,请回答下列问题: (1)用P、V操作管理这些并发进程时,应怎样定义信号量?写出信号量的初值以及信号量各种取值的含义。 (2)根据所定义的信号量,把应执行的P、V操作填入下述程序中,以保证进程能够正确地并发执行。 Cobegin PROCESS Pi(i=1,2,…) Begin 进入售票厅; 购票; 退出; End;

信号量读者写者问题

实验报告 Unix下C 课程名 称: 读者写者问题 实验项 目: 姓 名: 专 网络工程 业: 网络 班 级: 学 号:

指导老 师: 计算机科学与技术学院 实验教学中心 2013 年12 月22

目录

一、课程设计目的及意义 l.用信号量来实现读者写者问题。 2.理解和运用信号量、PV原语、进程间的同步互斥关系等基本知识。 3.通过研究Linux的线程机制和信号量实现读者写者(Reader-Writer)问题并发控制。 二、课程设计内容 在windows或者linux环境下编写一个控制台应用程序,本次课程设计在操作系统:Linux下,使用的编程语言为C语言。该程序运行时能创建N个线程,其中既有读者线程又有写者线程,它们按照事先设计好的测试数据进行读写操作。用信号量和PV操作实现读者/写者问题。 三、总体设计 读者/写者问题的描述如下: 有一个被许多进程共享的数据区,这个数据区可以是一个文件,或者主存的一块空间,甚至可以是一组处理器寄存器。有一些只读取这个数据区的进程(reader)和一些只往数据区中写数据的进程(writer)。以下假设共享数据区是文件。这些读者和写者对数据区的操作必须满足以下条件:读—读允许;读—写互斥;写—写互斥。这些条件具体来说就是: (1)任意多的读进程可以同时读这个文件; (2)一次只允许一个写进程往文件中写;

程访问文件; (4)写进程执行写操作前,应让已有的写者或读者全部退出。这说明当有读者在读文件时不允许写者写文件。 四、详细设计 读者-写者的读写限制 1)写-写互斥,即不能有两个写者同时进行写操作 2)读-写互斥,即不能同时有一个读者在读,同时却有一个写者在写 3)读读允许,即可以有2个以上的读者同时读 将所有的读者和所有的写者分别放进两个等待队列中,当读允许时就让读者队列释放一个或多个读者,当写允许时,释放第一个写者操作。读者写者问题的定义如下:有一个许多进程共享的数据区,这个数据区可以是一个文件或者主存的一块空间;有一些只读取这个数据区的进程(Reader)和一些只往数据区写数据的进程(Writer),此外还需要满足以下条件: (1)任意多的读进程可以同时读这个文件; (2)一次只允许一个写进程往文件中写;

用信号量机制实现的写者优先的算法如

用信号量机制实现的写者优先的算法如: Var Mut1,Mut2,Wmutex,Fmutex:Semaphore; Rcount,Wcount:integer; Mut1:=Mut2:=WMutex:=Fmutex:=1; Rcount:=Wcount:=0; //Fmutex --> 读者写者互斥 //WMutex --> 写者互斥 //Mut1 --> access to Rcount && 竞争Fmutex //Mut2 --> access to Wcount Writer:begin Wait(Mut1); Wcount:=Wcount+1; If Wcount=1 then Wait(Fmutex); //如有读者,写者阻塞在此处 Signal(Mut1); Wait(WMutex); 写操作; Signal(Wmutex); Wait(Mut1); Wcount:=Wcount-1; If Wcount=0 then Signal(Fmutex); Signal(Mut1); end Reader:begin Wait(Mut1); //读者需要先申请Mut1,如果有写者在等待Fmutex,则读者被阻塞,写者优先 Signal(Mut1); //立即释放Mut1,使写者可以随时申请到Mut1 Wait(Mut2); Rcount:=Rcount+1; If Rcount=1 then Wait(Fmutex); //第一个读者进入时,申请Fmutex;如有写者,第一个读者会阻塞在此处 Signal(Mut2); 读操作; Wait(Mut2); Rcount:=Rcount-1; If Rcount=0 then Signal(Fmutex); //最后一个读者退出时,释放Fmutex Singal(Mut2); end

操作系统练习题三四五章

第三章进程管理练习题 一、选择题 1.如果信号量S的值是0,此时进程A执行P(S)操作,那么,进程A会()。 A.继续运行 B.进入阻塞态,让出CPU C.进入就绪态,让出CPU D.继续运行,并唤醒S队列头上的等待进程 2. 正在运行的进程在信号量S上操作P操作之后,当S<0,进程将进入信号量的()。 A.等待队列 B.提交队列 C.后备队列 D.就绪队列 3.在非剥夺调度方式下,运行进程执行V原语后,其状态()。 A.不变 B.要变 C.可能要变 D.可能不变 4. 一个进程被唤醒,意味着()。 A.改进程重新占有了CPU B.进程状态变为就绪 C.它的优先权变为最大 D.其PCB移至就绪队列的队首 5.. 系统感知进程的唯一实体是()。 A.JCB B.FCB C.PCB D.SJT 6. 一进程在某一时刻具有()。 A.一种状态 B.二种状态 C.三种状态 D.四种状态 7. 进程从运行状态变为等待的原因可能是()。 A.输入/输出事件发生 B.时间片到 C.输入/输出事件完成 D.某个进程被唤醒 8. 进程创建原语的任务是()。 A.为进程编制程序 B.为进程建立PCB表 C.为进程分配CPU D.为进程分配所需的各种资源 9. 进程被创建后即进入()排队。 A.阻塞队列 B.就绪队列 C.缓冲队列 D.运行队列 10.在操作系统中,进程是一个具有一定独立功能的程序在某个数据集上的一次。 A)等待活动 B)运行活动 C)单独操作 D)关联操作 11.下面对进程的描述中,错误的是。 A)进程是动态的概念 B)进程执行需要处理机 C)进程是有生命期的 D)进程是指令的集合

Linux--sem_wait sem_post信号量操作进本函数

信号量的数据类型为结构sem_t,它本质上是一个长整型的数。函数sem_init()用来初始化一个信号量。它的原型为: extern intsem_init __P ((sem_t *__sem, int __pshared, unsigned int __value)); sem为指向信号量结构的一个指针;pshared不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享;value给出了信号量的初始值。 函数sem_post( sem_t *sem )用来增加信号量的值。当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不在阻塞,选择机制同样是由线程的调度策略决定的。 函数sem_wait( sem_t *sem )被用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少。函数sem_trywait ( sem_t *sem )是函数sem_wait()的非阻塞版本,它直接将信号量sem的值减一。 函数sem_destroy(sem_t *sem)用来释放信号量sem。 信号量用sem_init函数创建的,下面是它的说明: #include intsem_init (sem_t *sem, intpshared, unsigned int value); 这个函数的作用是对由sem指定的信号量进行初始化,设置好它的共享选项,并指定一个整数类型的初始值。pshared参数控制着信号量的类型。如果pshared的值是0,就表示它是当前里程的局部信号量;否则,其它进程就能够共享这个信号量。我们现在只对不让进程共享的信号量感兴趣。(这个参数受版本影响),pshared传递一个非零将会使函数调用失败。 这两个函数控制着信号量的值,它们的定义如下所示: [cpp]view plaincopy 1.#include 2.int sem_wait(sem_t * sem); 3.int sem_post(sem_t * sem); 这两个函数都要用一个由sem_init调用初始化的信号量对象的指针做参数。 sem_post函数的作用是给信号量的值加上一个“1”,它是一个“原子操作”---即同时对同一个信号量做加“1”操作的两个线程是不会冲突的;而同时对同一个文件进行读、加和写操作的两个程序就有可能会引起冲突。信号量的值永远会正确地加一个“2”--因为有两个线程试图改变它。 sem_wait函数也是一个原子操作,它的作用是从信号量的值减去一个“1”,但它永远会先等待该信号量为一个非零值才开始做减法。也就是说,如果你对一个值为2的信号量调用sem_wait(),线程将会继续执行,

操作系统(进程管理)习题与答案1

一、单选题 1、关于进程控制块的描述,如下存在问题的选项是()。 A.操作系统控制和管理并发执行进程的依据 B.进程存在的惟一标志,离散存放于内存空间或对应程序的文件目录项中 C.进程实体的一部分,是拥有描述进程情况及控制进程运行所需的全部信息的记录性数据结构 D.使一个在多道程序环境下不能独立运行的程序,成为一个能独立运行的基本单位,一个能与其它进程并发执行的进程 正确答案:B 2、进程标识符和进程控制块的分配可能发生在进程的()阶段。 A.阻塞 B.挂起 C.创建 D.终止 正确答案:C 3、当一个进程被()时,可能会发生处理器的调度。 ①终止;②挂起;③唤醒;④阻塞 A.①②④ B.①③④ C.①②③④ D.①④ 正确答案:C

4、对于系统服务进程而言,如果当前没有任务,便会引发自身的()事件。 A.进程阻塞 B.进程唤醒 C.进程终止 D.进程挂起 正确答案:A 5、引起进程重新调度的原因不包括()。 A.进程放弃处理器 B.进程从核心态返回用户态 C.进程执行系统调用和陷入内核态 D.时钟中断 正确答案:C 6、关于进程同步机制基本准则:当无进程处于某临界资源所对应的临界区时,可允许一个请求进入(该临界资源所对应的)临界区的进程立即进入自己的临界区,这称之为()。 A.忙则等待 B.有限等待 C.空闲让进 D.让权等待 正确答案:C 7、关于进程同步机制基本准则:当已有进程进入自己的对应于某临界资源的临界区时,所有企图进入该临界资源所对应临界区的进程必须等待,这称之为()。 A.循环等待

B.忙则等待 C.有限等待 D.让权等待 正确答案:B 8、关于进程同步机制基本准则:对要求访问临界资源的进程,应保 证该进程能在有限时间内进入自己的临界区,这称之为()。 A.忙则等待 B.循环等待 C.有限等待 D.让权等待 正确答案:C 9、进程同步机制应遵循让权等待准则,故而当一个进程不能进入自 己的临界区时,其应当释放()。 A.处理器 B.I/O设备 C.内存空间 D.外存空间 正确答案:A 10、利用硬件指令能有效地实现进程互斥,但它却不能满足 ()的准则,造成了处理器时间的浪费,而且也很难将它用 于解决较复杂的进程同步问题。 A.忙则等待 B.空闲让进 C.让权等待 D.有限等待

利用信号量机制解决哲学家进餐问题

利用信号量机制解决哲学家进餐问题

————————————————————————————————作者:————————————————————————————————日期:

成绩:课程设计报告 课程名称:课程设计(UNIX程序设计) 设计题目:利用信号量机制解决哲学家进餐问题 姓名: 专业:网络工程 班级: 学号: 计算机科学与技术学院 网络系 2013年12月28日

设计项目:利用信号量机制解决哲学家进餐问题 一、选题背景 1965年,数学家迪杰斯特拉提出,并成为经典的IPC问题—哲学家进餐问题。该问题的简单描述如下:五个哲学家围坐在一张圆桌周围,每个哲学家面前都一盘通心粉。由于通心粉很滑,需要两把叉子才能夹住。哲学家的生活中有两种交替活动时段,吃饭(EATING)和思考(THINKING)。当一个哲学家觉得饿了时,他就试图分两次去取左手边和右手边的叉子,每次拿一把,但不分次序。如果成功拿到两把叉子,就进入吃饭状态,吃完后放下叉子继续思考。 二、设计思路 1.每个哲学家的行为活动状态为两种:进餐(EATING)和思考(THINKING)。因此创建一个有5个元素的状态数组,每个数组元素的状态值为EATING或者THINKING。 2.五个哲学家围坐成一圈,每两个人中间有一个叉子,即每个哲学家的边和右边有一个叉子,但这个叉子需要和旁边的邻居竞争使用。对于每一个哲学家来说,其只有成功获得两个叉子,才能进入进餐状态。在进完餐后,需要成功放下手中的两个叉子,才能进入思考的状态。换个角度的描述就是,每个哲学家查询左右边的邻居当前状态,如果左右的邻居当前状态都为THINKING,则该哲学家可以进餐;如果左右邻居当前状态不都是THINKING,则哲学家不能进餐。因此可以为每一个哲学家设置一个信号量,来描述哲学家的活动状态。 3.因为五只叉子做多只能允许两个哲学家进餐,所以可以将桌子作为一个临界资源。通过设置一个互斥信号量来限制对临界资源的访问数。 4.创建两个动作函数,对应于每个哲学家的获取两把叉子和放下两把叉子的动作。而每个动作都需要对互斥信号量和哲学家信号量进行访问操作,因此创建原子操作P和原子操作V,来执行对信号量的消耗和释放操作。 5.利用父进程创建五个子进程来模拟五个哲学家,在每个子进程中执行PHILOSOPHER (phi_num)函数来模拟每个哲学家进入哲学家进餐问题活动。 三、主要问题的解决方法和关键技术 1.共享状态数组问题。 问题描述:因为状态数组是共享的,而每个模拟哲学家的子进程是相互独立的,有自己的地址空间,在进程之间共享使用状态数组出现问题。 解决方法:父进程通过利用UNIX系统进程通信机制中共享内存机制的shmget()和shmat系统调用创建一个共享内存区,并将状态数组地址链接到进程地址空间,成功的解决了该问题。 2.信号量创建及初始化问题 问题描述:整个程序使用两个不同的信号量,一个是记录型信号量数组,一个是互斥

相关主题
文本预览
相关文档 最新文档