- 作业
- 用代码实现汽车发动以及停车,乘客上车,售票员等功能
#include
#include
#include //fork
#include
#include//kill()
#include //signal
pid_t pid=-1;
//司机:到站停车--->SIGINT Ctrl+c
// 关门开车--->SIGUSR1
void handleDrive(int sig)
{
if(SIGINT==sig)
{
printf("到站了...\n");
sleep(1);
printf("司机开始停车\n");
sleep(1);
int ret = 0;
ret = kill(pid,SIGUSR2);//发送信号给子进程,发送信号给售票员让她开门
if (-1 == ret)
{
perror("kill");
}
}
else if(SIGUSR1==sig)
{
printf("司机开始开车\n");
sleep(1);
printf("车正在跑\n");
sleep(1);
}
}
//管理员:开门--->SIGUSR2
void handleConductor(int sig)
{
if(SIGUSR2==sig)
{
printf("售票员开门\n");
sleep(1);
printf("乘客上车\n");
sleep(1);
printf("售票员关门\n");
sleep(1);
kill(getppid(),SIGUSR1);//售票员发送信号给司机开车
}
}
int main()
{
pid=fork();
if(pid>0)//drive
{
signal(SIGINT,handleDrive);//注册信号
signal(SIGUSR1,handleDrive);
printf("司机等待售票员做好开车准备\n");
while(1)
{
pause();
}
}
else if(pid==0)//conductor
{
signal(SIGINT,SIG_IGN);
signal(SIGUSR2,handleConductor);
sleep(1);
//发送和一个开车信号,让其开车
kill(getppid(),SIGUSR1);
while(1)
{
pause();//有信号则返回,无信号就挂起
}
}
else if(pid==-1)//创建进程失败
{
perror("fork");
return -1;
}
return 0;
}
线程
并发执行
- 同时存在,同时运行.(并不是同时运行的,分给A10ms,运行完之后,则挂起,再给B10ms.由于时间很短,人为看不出来,以为是同时运行的)
时间片
创建线程
- 编译时一定要加-pthread
- 以下程序:测试两个线程是否同时运行
- 是交替执行,不是并发
#include //pthread_create()
#include
#include//strerror()
#include //errno
#include
void *thread_run(void *arg)
{
while(1)
{
printf("this is thread_run...\n");
sleep(1);
}
return NULL;
}
int main()
{
pthread_t thread;
int ret=0;
ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为NULL
if(0!=ret)
{
printf("errno:%d,error:%s\n",ret,strerror(ret));
return -1;
}
while(1)
{
printf("this is main...\n");
sleep(1);
}
return 0;
}
- 5s之后将线程结束,但是main函数继续执行
//使用return,只能结束当前线程,exit会将该线程所属的进程挂掉,当然线程也会挂断
- 一个进程创建线程后,创建的线程同属于该进程,不独立于进程,共享进程的所有资源.
- 线程是最小的执行单元,若一个进程没有创建线程,我们既可以把它看作是进程,也可以是相当于线程,若一个进程创建线程之后,我们可以将该线程称之为主线程,一个进程可以创建多个线程,线程之间资源共享
#include //pthread_create()
#include
#include//strerror()
#include //errno
#include
void *thread_run(void *arg)
{
int i=0;//将这个线程,5s之后结束
while(1)
{
printf("this is thread_run...\n");
sleep(1);
i++;
if(i==5)
{
return NULL;
}
}
return NULL;
}
int main()
{
pthread_t thread;
int ret=0;
ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为NULL
if(0!=ret)
{
printf("errno:%d,error:%s\n",ret,strerror(ret));
return -1;
}
while(1)
{
printf("this is main...\n");
sleep(1);
}
return 0;
}
- 使用exit之后,exit会将该线程所属的进程挂掉,当然线程也会挂断
#include //pthread_create()
#include
#include//strerror()
#include //errno
#include
void *thread_run(void *arg)
{
int i=0;//将这个线程,5s之后结束
while(1)
{
printf("this is thread_run...\n");
sleep(1);
i++;
if(i==5)
{
//使用return,只能结束当前线程,exit会将该线程所属的进程挂掉,当然线程也会挂掉
exit(1);
}
}
return NULL;
}
int main()
{
pthread_t thread;
int ret=0;
ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为NULL
if(0!=ret)
{
printf("errno:%d,error:%s\n",ret,strerror(ret));
return -1;
}
while(1)
{
printf("this is main...\n");
sleep(1);
}
return 0;
}
- 资源共享
#include //pthread_create()
#include
#include//strerror()
#include //errno
#include
int g_iData=999;
void *thread_run(void *arg)
{
//while(1)
{
printf("this is thread_run...iData=%d\n",g_iData);
g_iData++;
// sleep(1);
}
return NULL;
}
int main()
{
pthread_t thread;
int ret=0;
ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为NULL
if(0!=ret)
{
printf("errno:%d,error:%s\n",ret,strerror(ret));
return -1;
}
sleep(2);
// while(1)
{
printf("this is main...iData=%d\n",g_iData);
// sleep(1);
}
return 0;
}
- 没有将iData拷贝一份,而是资源共享
参数的传递
- 将地址传给他
#include //pthread_create()
#include
#include//strerror()
#include //errno
#include
#include
void *thread_run(void *arg)
{
while(1)
{
printf("this is thread_run...arg=%d\n",*(int *)arg);
printf("this is thread_run...arg=%d\n",(int)arg);
sleep(1);
}
return NULL;
}
int main()
{
pthread_t thread;
int ret=0;
int iArg=1999;
ret=pthread_create(&thread,NULL,thread_run,&iArg);//将参数的地址传给他
if(0!=ret)
{
printf("errno:%d,error:%s\n",ret,strerror(ret));
return -1;
}
while(1)
{
printf("this is main...\n");
sleep(1);
}
return 0;
}
#include //pthread_create()
#include
#include//strerror()
#include //errno
#include
#include
void *thread_run(void *arg)
{
while(1)
{
printf("this is thread_run...arg=%d\n",(int)arg);
sleep(1);
}
return NULL;
}
int main()
{
pthread_t thread;
int ret=0;
int iArg=1999;
pthread_create(&thread,NULL,thread_run,(void *)iArg);//或者(void *)1888效果如上
if(0!=ret)
{
printf("errno:%d,error:%s\n",ret,strerror(ret));
return -1;
}
while(1)
{
printf("this is main...\n");
sleep(1);
}
return 0;
}
- 将结构体传给他
#include //pthread_create()
#include
#include//strerror()
#include //errno
#include
#include
typedef struct Student
{
int iId;
char caName[32];
float fScore;
}Student;
void *thread_run(void *arg)
{
while(1)
{
Student *pStu=(Student *)arg;
printf("id:%d,name:%s,score:%.2f\n",pStu->iId,pStu->caName,pStu->fScore);
sleep(1);
}
return NULL;
}
int main()
{
pthread_t thread;
int ret=0;
int iArg=1999;
Student stu={1001,"zhangsan",89};
ret=pthread_create(&thread,NULL,thread_run,&stu);
// ret=pthread_create(&thread,NULL,thread_run,(void *)stu);//这种方法不可以
if(0!=ret)
{
printf("errno:%d,error:%s\n",ret,strerror(ret));
return -1;
}
while(1)
{
printf("this is main...\n");
sleep(1);
}
return 0;
}
pthread cancel(发送一个请求)
#include //pthread_create()
#include
#include//strerror()
#include //errno
#include
void *thread_run(void *arg)
{
//在线程函数中调用pthread_setcancelstate来设置
//不同意结束线程请求,阻塞线程结束请求
//直到线程允许接收线程结束请求
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
while(1)
{
printf("this is thread_run...\n");
sleep(1);
}
return NULL;
}
int main()
{
pthread_t thread;
int ret=0;
ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为NULL
if(0!=ret)
{
printf("errno:%d,error:%s\n",ret,strerror(ret));
return -1;
}
sleep(3);
//发送一个结束线程请求给指定线程,默认情况下,线程会同意该结束线程请求,还可以设置不同意
pthread_cancel(thread);//3秒之后让线程挂掉
while(1)//测试是否挂掉,如果挂掉了,则会打印this is main
{
printf("this is main...\n");
sleep(1);
}
return 0;
}
pthread_exit
#include //pthread_create()
#include
#include//strerror()
#include //errno
#include
void *thread_run(void *arg)
{
//在线程函数中调用pthread_setcancelstate来设置
//不同意结束线程请求,阻塞线程结束请求
//直到线程允许接收线程结束请求
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
while(1)
{
printf("this is thread_run...\n");
sleep(1);
}
return NULL;
}
int main()
{
pthread_t thread;
int ret=0;
ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为NULL
if(0!=ret)
{
printf("errno:%d,error:%s\n",ret,strerror(ret));
return -1;
}
sleep(3);
//若存在主线程中,如果含有其他线程存在,则阻塞等待其他线程结束明若没有其他线程,则结束
pthread_exit(NULL);
while(1)//测试是否挂掉,如果挂掉了,则会打印this is main
{
printf("this is main...\n");
sleep(1);
}
return 0;
}
- 一直等待其他线程的结束,则退出.如果其他线程结束,则退出
#include //pthread_create()
#include
#include//strerror()
#include //errno
#include
void *thread_run(void *arg)
{
//在线程函数中调用pthread_setcancelstate来设置
//不同意结束线程请求,阻塞线程结束请求
//直到线程允许接收线程结束请求
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
while(1)
{
printf("this is thread_run...\n");
sleep(1);
break;//则执行一次,退出程序
}
return NULL;
}
int main()
{
pthread_t thread;
int ret=0;
ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为NULL
if(0!=ret)
{
printf("errno:%d,error:%s\n",ret,strerror(ret));
return -1;
}
sleep(3);
//若存在主线程中,如果含有其他线程存在,则阻塞等待其他线程结束,若没有其他线程,则结束
pthread_exit(NULL);
while(1)//测试是否挂掉,如果挂掉了,则会打印this is main
{
printf("this is main...\n");
sleep(1);
}
return 0;
}
#include //pthread_create()
#include
#include//strerror()
#include //errno
#include
void *thread_run(void *arg)
{
//在线程函数中调用pthread_setcancelstate来设置
//不同意结束线程请求,阻塞线程结束请求
//直到线程允许接收线程结束请求
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
while(1)
{
printf("this is thread_run...\n");
sleep(1);
break;//则执行一次,退出程序
pthread_exit(NULL);//如果放在此处,则表示结束所属线程
}
return NULL;
}
int main()
{
pthread_t thread;
int ret=0;
ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为NULL
if(0!=ret)
{
printf("errno:%d,error:%s\n",ret,strerror(ret));
return -1;
}
sleep(3);
while(1)//测试是否挂掉,如果挂掉了,则会打印this is main
{
printf("this is main...\n");
sleep(1);
}
return 0;
}
pthread_join等待线程结束,若线程在运行,则阻塞等待,若线程结束,立即返回,第一个参数:要等待的线程,第二个参数:要来获得线程的返回值
#include //pthread_create()
#include
#include//strerror()
#include //errno
#include
void *thread_run(void *arg)
{
while(1)
{
printf("this is thread_run...\n");
sleep(1);
}
return NULL;
}
int main()
{
pthread_t thread;
int ret=0;
ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为NULL
if(0!=ret)
{
printf("errno:%d,error:%s\n",ret,strerror(ret));
return -1;
}
//等待线程结束,若线程在运行,则阻塞等待,若线程结束,立即返回,第一个参数:要等待的线程,第二个参数:要来获得线程的返回值
pthread_join(thread,NULL);
while(1)
{
printf("this is main...\n");
sleep(1);
}
return 0;
}
#include //pthread_create()
#include
#include//strerror()
#include //errno
#include
void *thread_run(void *arg)
{
while(1)
{
printf("this is thread_run...\n");
sleep(1);
break;
}
return NULL;
}
int main()
{
pthread_t thread;
int ret=0;
ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为NULL
if(0!=ret)
{
printf("errno:%d,error:%s\n",ret,strerror(ret));
return -1;
}
//等待线程结束,若线程在运行,则阻塞等待,若线程结束,立即返回,第一个参数:要等待的线程,第二个参数:要来获得线程的返回值
pthread_join(thread,NULL);
while(1)
{
printf("this is main...\n");
sleep(1);
}
return 0;
}
pthread_addNum
#include //pthread_create()
#include
#include//strerror()
#include //errno
#include
int g_iData=0;
void *thread_run(void *arg)
{
while(1)
{
++g_iData;
printf("thread :data=%d\n",g_iData);
}
return NULL;
}
int main()
{
pthread_t thread;
int ret=0;
ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为NULL
if(0!=ret)
{
printf("errno:%d,error:%s\n",ret,strerror(ret));
return -1;
}
while(1)
{
++g_iData;
printf("main :data=%d\n",g_iData);
}
return 0;
}
- g_iData=0;A线程++g_iData,如果线程A时间足够的话,则g_iData=1;B线程再执行,则变为2;
- 若A时间片不够,虽然++了但++后的值还没有返回到g_iData里,所以B线程++后的值仍然为1
- 如下,会出现中断的情况
- 解决以上情况,则定义一个原子锁
#include //pthread_create()
#include
#include//strerror()
#include //errno
#include
pthread_mutex_t mutex; //互斥量或者称为锁
int g_iData=0;
void *thread_run(void *arg)
{
while(1)
{
//使用pthread_mutex_lock和pthread_mutex_unlock
//使它们之间的语句合成原子操作
pthread_mutex_lock(&mutex);
++g_iData;
printf("thread :data=%d\n",g_iData);
pthread_mutex_unlock(&mutex);
}
return NULL;
}
int main()
{
//初始化互斥量,NULL表示使用默认属性初始化该互斥量
pthread_mutex_init(&mutex,NULL);//使用他的默认属性进行初始化
pthread_t thread;
int ret=0;
ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为NULL
if(0!=ret)
{
printf("errno:%d,error:%s\n",ret,strerror(ret));
return -1;
}
while(1)
{
pthread_mutex_lock(&mutex);
++g_iData;
printf("main :data=%d\n",g_iData);
pthread_mutex_unlock(&mutex);
}
return 0;
}
- 这样就不会出现中断的情况
一个线程从文件读取数据,另一个线程打印出来
- 先通过以前的代码,在文件里写入几个同学的信息
#include
#include //write() read()
#include //errno
#include //strerror()
/*open()*/
#include
#include
#include
#include //pthread_create
pthread_mutex_t mutex;
#define NAME_LEN 32
typedef struct Student
{
int iId;
char caName[NAME_LEN];
char cSex;
float fScore;
}Student;
int myOpen(const char *pathname)
{
int fd = -1;
if (NULL != pathname)
{
fd = open(pathname, O_RDONLY | O_CREAT
, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (-1 == fd)
{
printf("open error: %s\n", strerror(errno));
}
}
return fd;
}
int g_iSign = 0;
void *read_thread(void *arg)
{
int fd = -1;
fd = myOpen("stu.info");
if (-1 != fd)
{
int ret = -1;
Student *pStu = (Student *)arg;
while (1)
{
if (0 == g_iSign)
{
pthread_mutex_lock(&mutex);
memset(pStu, '\0', sizeof(Student));
ret = read(fd, pStu, sizeof(Student));
if (0 == ret)
{
printf("reached the file end\n");
pthread_mutex_unlock(&mutex);
g_iSign = 1;
break;
}
else if (-1 == ret)
{
printf("read error:%s\n", strerror(errno));
pthread_mutex_unlock(&mutex);
g_iSign = 1;
break;
}
pthread_mutex_unlock(&mutex);
g_iSign = 1;
}
}
close(fd);
}
return NULL;
}
void *print_thread(void *arg)
{
Student *pStu = (Student *)arg;
int i = 0;
while (1)
{
if (1 == g_iSign)
{
pthread_mutex_lock(&mutex);
if (0 == pStu->iId)
{
pthread_mutex_unlock(&mutex);
break;
}
printf("id:%d, name:%s, sex:%c, score:%.1f\n"
, pStu->iId, pStu->caName
, pStu->cSex, pStu->fScore);
pthread_mutex_unlock(&mutex);
g_iSign = 0;
}
}
return NULL;
}
int main(void)
{
pthread_mutex_init(&mutex, NULL);
Student stu;
pthread_t pthr_read;
pthread_t pthr_show;
pthread_create(&pthr_read, NULL, read_thread, &stu);
pthread_create(&pthr_show, NULL, print_thread, &stu);
pthread_join(pthr_read, NULL);
pthread_join(pthr_show, NULL);
return 0;
}
信号量(sem_wait)
//int sem_init();//pshared
#include
#include //write() read()
#include //errno
#include //strerror()
/*open()*/
#include
#include
#include
#include //pthread_create
#include
pthread_mutex_t mutex;
sem_t read_sem;//读的信号量
sem_t print_sem;//显示的信号量
#define NAME_LEN 32
typedef struct Student
{
int iId;
char caName[NAME_LEN];
char cSex;
float fScore;
}Student;
int myOpen(const char *pathname)
{
int fd = -1;
if (NULL != pathname)
{
fd = open(pathname, O_RDONLY | O_CREAT
, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (-1 == fd)
{
printf("open error: %s\n", strerror(errno));
}
}
return fd;
}
void *read_thread(void *arg)
{
int fd = -1;
fd = myOpen("stu.info");
if (-1 != fd)
{
int ret = -1;
Student *pStu = (Student *)arg;
while (1)
{
//如果read_sem大于0,接着往下执行,并且将该变量减1,如果等于0,则阻塞,直到该值大于0
sem_wait(&read_sem);//此时read_sem=1
pthread_mutex_lock(&mutex);
memset(pStu, '\0', sizeof(Student));
ret = read(fd, pStu, sizeof(Student));
if (0 == ret)
{
printf("reached the file end\n");
pthread_mutex_unlock(&mutex);
sem_post(&print_sem);//出错了,发送这个信号
break;
}
else if (-1 == ret)
{
printf("read error:%s\n", strerror(errno));
pthread_mutex_unlock(&mutex);
sem_post(&print_sem);//出错了,发送这个信号
break;
}
pthread_mutex_unlock(&mutex);
sem_post(&print_sem);//出错了,发送这个信号
}
close(fd);
}
return NULL;
}
void *print_thread(void *arg)
{
Student *pStu = (Student *)arg;
int i = 0;
while (1)
{
//如果print_sem大于0,接着往下执行,并且将该变量减1,如果等于0,则阻塞,直到该值大于0
sem_wait(&print_sem);
pthread_mutex_lock(&mutex);
if (0 == pStu->iId)
{
pthread_mutex_unlock(&mutex);
sem_post(&read_sem);
break;
}
printf("id:%d, name:%s, sex:%c, score:%.1f\n"
, pStu->iId, pStu->caName
, pStu->cSex, pStu->fScore);
pthread_mutex_unlock(&mutex);
//将信号量的值加1
sem_post(&read_sem);
}
return NULL;
}
int main(void)
{
pthread_mutex_init(&mutex, NULL);
sem_init(&read_sem,0,1);//对信号量的初始化,必须先读才能再显示,将read_sem的值置为1
sem_init(&print_sem,0,0);//将print_sem的值置为0
Student stu;
pthread_t pthr_read;
pthread_t pthr_show;
pthread_create(&pthr_read, NULL, read_thread, &stu);
pthread_create(&pthr_show, NULL, print_thread, &stu);
pthread_join(pthr_read, NULL);
pthread_join(pthr_show, NULL);
return 0;
}
用代码模仿5个哲学家进餐问题
- 创建5根筷子(5个信号量创建一组信号量)
- 创建5科学家
- 获得筷子
- 放下筷子
- 继续思考
int semop(int semid, struct sembuf *sops, unsigned nsops);
参数
- semid:信号集的识别码,可通过semget获取。
- sops:指向存储信号操作结构的数组指针,信号操作结构的原型如下
struct sembuf
{
unsigned short sem_num; /* semaphore number */
short sem_op; /* semaphore operation */
short sem_flg; /* operation flags */
};
- 这三个字段的意义分别为:
- sem_num:操作信号在信号集中的编号,第一个信号的编号是0。
- sem_op:
- 1, 如果其值为正数,该值会加到现有的信号内含值中。
通常用于释放所控资源的使用权; - 2, 如果sem_op的值为负数,而其绝对值又大于信号的现值,
操作将会阻塞,直到信号值大于或等于sem_op的绝对值。
通常用于获取资源的使用权; - 3, 如果sem_op的值为0,如果没有设置IPC_NOWAIT,
则调用该操作的进程或者线程将暂时睡眠,直到信号量的值为0; 否则,进程或者线程不会睡眠,函数返回错误EAGAIN。
- sem_flg:信号操作标志,可能的选择有两种
- 1, IPC_NOWAIT //对信号的操作不能满足时,semop()不会阻塞,
并立即返回,同时设定错误信息。 - 2, SEM_UNDO //程序结束时(不论正常或不正常),
保证信号值会被重设为semop()调用前的值。
这样做的目的在于避免程序在异常情况下结束时
未将锁定的资源解锁,造成该资源永远锁定。
- nsops:信号操作结构的数量,恒大于或等于1。
#include
#include
#include
#include //perror()
#include
#include
#include
#include
#include
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
void getChopsticks(int iNum,int *semfd)
{
int iLeft=iNum;
int iRight=(iNum+1)%5;
struct sembuf semope[2]={{iLeft,-1,0},
{iRight,-1,0}};
semop(*semfd,semope,2);//拿筷子,获得左右两边的筷子
}
void putChopsticks(int iNum,int *semfd)
{
int iLeft=iNum;
int iRight=(iNum+1)%5;
struct sembuf semope[2]={{iLeft,1,0},
{iRight,1,0}};
semop(*semfd,semope,2);//拿筷子,获得左右两边的筷子
}
void thinkAndEat(int iNum,int *semfd)
{
while(1)
{
printf("%d say:I am thinking...\n",iNum);
/*拿筷子吃饭*/
getChopsticks(iNum,semfd);
sleep(1);
printf("%d say:I am eatting...\n",iNum);
/*放下筷子*/
putChopsticks(iNum,semfd);
printf("%d say:I am puting chopsticks...\n",iNum);
sleep(1);
}
}
int main(void)
{
int semfd=-1;
//获得信号量集的标识,若信号量集不存在则创建
semfd=semget(0x1024,5,IPC_CREAT | 0777);//5,代表5个信号量
if(-1==semfd)
{
perror("semget");
return -1;
}
//对信号集中的信号量进行赋值
union semun sem;
sem.val=1;
int i=0;
for(;i<5;i++)
{
if(-1==semctl(semfd,i,SETVAL,sem))
{
perror("semctl");
return -1;
}
}
//创建5个哲学家进程
int iNum=0;//用来保存表示第几个科学家
pid_t pid=-1;
for(i=0;i<4;i++)
{
pid=fork();
if(pid>0)//parent
{
iNum=4;
}
else if(pid==0)//child
{
iNum=i;
break;//
}
else if(pid==-1)//error
{
return -1;
}
}
thinkAndEat(iNum,&semfd);
return 0;
}