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 "<
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"<
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<
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!!"<
}
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;
}