红联Linux门户
Linux帮助

信号量--操作系统实验总结

发布时间:2008-05-16 10:08:55来源:红联作者:gobeta
这个信号量的实验困扰了我好几天,WINDOWS下的好调,LINUX却总是出错.今晚上终于搞定了,总结一下教训:

LINUX下信号量控制线程同步问题,C语言:

使用到的关键内容:

1)P,V操作的数据结构 struct sembuf P,V;

2)给信号量赋初值的参数数据结构 union semun arg;

3)信号量标识: int semid;

4)申请信号量: semid = semget(IPC_PRIVATE,1,IPC_0666|IPC_CREAT);

(第一个参数为由系统产生key值,也可以由用户使用具体的整型数值作为key值的指定,后者适用于非家族关系的 任意进程之间,它们需要事先约定需要共享使用的信号量的外部标识.在非父子进程中如果使用IPC_PRIVATE,会因为key的随即值而分别对应不同的信号量集,而非同一个key所对应的信号量集.

第二个参数标识信号量集中有多少信号量;

第三个参数表示操作权限,0666表示任意用户可读可写,只设置semflg的IPC_CREAT位,则创建一个信号量集,如果该信号量集已经存在,则返回其标识符)

5)对信号量赋初值: arg.val = 初值

semctl(semid,0,SETVAL,arg);

6)定义信号量的PV操作:

P.sem_num = 0;
P.sem_op = -1; //表示为减1操作
P.sem_flg = SEM_UNDO;
V.sem_num = 0;
V.sem_op = 1; //表示为加1操作
V.sem_flg = SEM_UNDO;

7)对信号量执行PV操作:

semop(semid,&P,1);

semop(semid,&V,1);

8)撤销信号量

semctl(semid,IPC_RMID,0);

遇到问题:

1,头文件:

包含过多的头文件容易出问题,比如同时包含 linux/sem.h 和 sys/sem.h 就会报错说定义冲突

2,pthread 相关函数不识别:

要在编译的时候加参数 -lpthread

>>gcc -o main main.c -lpthread

>>./main

3,for循环出错:

注意C语言和C++的区别,C语言不允许for(int i=0;i
4,输出结果为乱码:

因为我在linux下运行,读取的文件是其下的.sxw文件,可能是编码不一致的问题导致乱码,我没有弄 清.sxw到底是什么编码,只是换了一个.c的文件,读取成功.

5,只有hReader[i]进程执行,hPrinter进程没有执行:

解决方法:在semop(printid,&V,1)后添加sleep(1)使其等待一段时间,再semop(mutexid,&V,1)

不然,可能在hPrinter还没醒来把hReader阻塞,hReader就先把hPrinter阻塞了.

这是我的理解,有谁发现不是这样,记得提醒我啊~



源代码:

#include
#include
#include
#include
#include
#include

int mutexid; //信号量标识 mutexid
int printid; //信号量标识 printid
int readid; //信号量标识 readid
struct sembuf P; //P操作
struct sembuf V; //V操作
union semun arg1; //给信号量赋初值的结构
union semun arg2; //同上
union semun arg3; //同上
FILE *fp; //文件指针

int TotalWords = 0;
int TotalOddWords = 0;
int TotalEvenWords = 0;

void m_print(void *Arg);
void m_read(void *Arg);



int main()
{
mutexid = semget(IPC_PRIVATE,1,0666|IPC_CREAT); //申请只有一个信号量的信号量集
printid = semget(IPC_PRIVATE,1,0666|IPC_CREAT);
readid = semget(IPC_PRIVATE,1,0666|IPC_CREAT);

arg1.val = 1; //赋初值
arg2.val = 0;
arg3.val = 1;

semctl(mutexid,0,SETVAL,arg1); //通过将arg和信号量标识联系起来给信号量赋初值
semctl(printid,0,SETVAL,arg2);
semctl(readid,0,SETVAL,arg3);

P.sem_num = 0;
P.sem_op = -1; //表示为减1操作
P.sem_flg = SEM_UNDO;
V.sem_num = 0;
V.sem_op = 1; //表示为加1操作
V.sem_flg = SEM_UNDO;

pthread_t hReader[3]; //声明线程句柄
pthread_t hPrinter;

if((fp=fopen("/root/abc.c","rt"))==NULL) //尝试打开文件
{
printf("Cannot open file strike any key exit!");
exit(1);
}

int i; //注意:C语言和C++不同,C语言不能在for循环中声明变量int i=0;
int j;
pthread_create(&hPrinter, NULL, (void *)m_print, NULL); //创建线程,注意参数的写法
for(i=0; i<3; i++)
{
pthread_create(&hReader[i], NULL, (void *)m_read, NULL);
}
for(j=0; j<3; j++)
{
pthread_join(hReader[j], NULL); //主线程等待子线程结束
}
pthread_join(hPrinter, NULL);
semctl(mutexid,IPC_RMID,0); //撤销信号量
semctl(readid,IPC_RMID,0);
semctl(printid,IPC_RMID,0);

return 0;

}


void m_print(void *Arg)
{
while(1)
{
semop(printdid,&P,1); //对信号量printid执行P操作
printf("This line includes ");
printf("%d",TotalWords);
printf(" words");
printf("%d",TotalEvenWords);
printf(" even words");
printf("%d",TotalOddWords);
printf(" odd words");

TotalWords = 0;
TotalEvenWords = 0;
TotalOddWords = 0;
semop(readid,&V,1); //对信号量readid执行V操作
}
}


void m_read(void *Arg)
{
while(1)
{
semop(readid,&P,1); //对信号量readid执行P操作
semop(mutexid,&P,1); //对信号量mutexid执行P操作
char ch;
int count = 0;
ch = fgetc(fp); //读取fp所指向的文件内容,放入ch
if(ch == EOF)
{
break;
}
while(ch!='\n')
{
if(ch == ' ')
{
if(count%2 == 0)
{
TotalEvenWords++;
}
else
{
TotalOddWords++;
}
TotalWords++;
count = 0;
}
else
{
count++;
}
putchar(ch); //将ch中的内容输出到屏幕
ch = fgetc(fp);
}
if(count%2 == 0)
{
TotalEvenWords++;
}
else
{
TotalOddWords++;
}
TotalWords++;
putchar('\n');
semop(printid,&V,1); //对信号量printid执行V操作
sleep(1); //等待一段时间
semop(mutexid,&V,1); //对信号量mutexid执行V操作
}

}


Windows下使用信号量,C++实现:

关键API:

1)WaitForSingleObject(p,WaitTime) 相当于 wait(p);

2)ReleaseSemaphore(s,1,NULL); 相当于 signal(s);

3)信号量句柄声明:

HANDLE mutex;
HANDLE p; //打印
HANDLE s; //统计

4)创建信号量:

mutex = CreateSemaphore(NULL,1,1,NULL);
p = CreateSemaphore(NULL,0,1,NULL);
s = CreateSemaphore(NULL,1,1,NULL);

第二个参数为初始值

5)声明线程句柄:

HANDLE thHd;

6)创建线程:

thHd = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&print,&Printer,0,&Printer.thId);

遇到的问题:

1)文件读写:

判断是否读到末尾用 bool infile.eof()

2)主线程等待子线程:

没有找到API,我只好用了while(1){}永久等待下去了......失败..

源代码:(写的比较罗嗦)

#include
#include
using std::cout;
using std::endl;
using std::ios;

#include
using std::fstream;
using std::ifstream;
using std::ofstream;

struct Thread
{
HANDLE thHd;
DWORD thId;
int index;
} Reader[3];

Thread Printer;
bool over = false;

HANDLE mutex;
HANDLE p; //打印
HANDLE s; //统计
DWORD WaitTime = 2000;
ifstream infile;
int TotalWords = 0;
int TotalOddWords = 0;
int TotalEvenWords = 0;

void print(Thread printer)
{
while(true)
{
if(WaitForSingleObject(p,WaitTime) == WAIT_OBJECT_0)
{
cout<<"This line includes "< < < TotalWords = 0;
TotalOddWords = 0;
TotalEvenWords = 0;
ReleaseSemaphore(s,1,NULL);
}
}
}

void read(Thread *th)
{

while(!over)
{
if(WaitForSingleObject(s,WaitTime) == WAIT_OBJECT_0)
{
if(WaitForSingleObject(mutex,WaitTime) == WAIT_OBJECT_0)
{
//cout<<"Thread"<index<
char ch;
int count = 0;
infile.get(ch);
if(infile.eof())
{
over = true;
}
else
{

while(ch!='\n')
{
if(ch == ' ')
{
if(count%2 == 0)
{
TotalEvenWords++;
}
else
{
TotalOddWords++;
}
TotalWords++;
count = 0;
}
else
{
count++;
}
cout< infile.get(ch);
if(infile.eof())
{
count--;
break;
}

}
count++;
if(count%2 == 0)
{
TotalEvenWords++;
}
else
{
TotalOddWords++;
}

TotalWords++;
cout<<'\n';
ReleaseSemaphore(p,1,NULL);
ReleaseSemaphore(mutex,1,NULL);
}

}
}
}
}

int main()
{
mutex = CreateSemaphore(NULL,1,1,NULL);
p = CreateSemaphore(NULL,0,1,NULL);
s = CreateSemaphore(NULL,1,1,NULL);
const char *file = "F:\\myFile.txt";
infile.open(file,ios::binary);
if(!infile)
{
cout<<"error!!"< return 0;
}
for(int i=0;i<3;i++)
{
Reader[i].index = i;
Reader[i].thHd = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&read,&Reader[i],0,&Reader[i].thId);
}
Printer.index = 0;
Printer.thHd = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&print,&Printer,0,&Printer.thId);
//infile.close();
while(1)
{}
return 0;
}
文章评论

共有 0 条评论