复习
线程和进程的区别
1) 线程不可以单独存在,依附于进程,进程结束,线程结束
2) 创建进程要分配所有内存(全局区、栈区、堆区、代码区),创建线程只分配栈区
void *fun(void *p)
{
int *q = p;
printf("%d\n", *q);
}
int a = 100;
ptread_create(&id, NULL, fun, &a);
默认情况优先级0, 堆栈大小8M
///给线程传递参数,可以是任何类型
用pthread_create的第四个参数,
void * 可以用来赋值,但是不可以++, -- , *p
线程间同步与互斥
互斥(两个或多个线程 共同访问一个共享资源, 两个线程只能有一个同时访问)
同步(两个线程访问共享资源有先后顺序, A->B->A->B)
互斥锁(mutex)
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);
用之前加锁
pthread_mutex_lock(&mutex);
用完解锁
pthread_mutex_unlock(&mutex);
信号量
#inlcude <semaphore.h> //sem
1 创建信号量
sem_t sem;
sem_init(&sem, 0, 3);
sem_init(&sem, 0, 1);
sem_init(&sem, 0, 0);
2 请求信号量
sem_wait(&sem); 信号值-1, 直到减到0, 阻塞
3 释放信号量
sem_post(&sem); 信号值+1
【线程间通信 使用全局变量即可】
【进程间内存都是独立的,不可以互相访问,那么进程间如何通信? linux系统从内核中拿出一块内存,供两个进程使用】
///进程间通信有 管道(无名管道和有名管道), 信号,消息队列,共享内存, 信号量, 套接字
1 管道(无名管道和有名管道)
管道的特点:
先进先出
无名管道(只能在父子进程之间使用)
int pipe(int fd[2]);
功能: 用于创建无名管道,一旦创建成功,就会传出2个文件描述符
fd[0] ---> 专门用于读操作(读端)
fd[1] ---> 专门用于写操作(写端)
如何读?
read(fd[0], buf, sizeof(buf));
如何写?
write(fd[1], buf, sizeof(buf));
例: 子进程 写入, 父进程 读出
#include <stdio.h>
#include <unistd.h>
int main()
{
int fd[2]; //没初始化,用来保存两个文件描述符
pipe(fd); //传出两个文件描述符 fd[0] fd[1]
int pid = fork();
if(pid == 0)
{ //子进程
close(fd[0]); //子进程关闭读端
write(fd[1], "hello", sizeof("hello"));
}
else if(pid > 0)
{
char buf[100] = { 0 };
close(fd[1]);
wait(NULL);
read(fd[0], buf, sizeof(buf)); //read 是阻塞的,管道中没数据,等
printf("read is %s\n", buf);
}
}
///
///练习,修改上面程序,父进程循环从键盘输入数据写入管道,子进程循环读出,父进程输入'0',结束
#include <stdio.h>
#include <unistd.h>
int main()
{
int fd[2]; //没初始化,用来保存两个文件描述符
char buf[100] = { 0 };
pipe(fd); //传出两个文件描述符 fd[0] fd[1]
int pid = fork();
if(pid == 0)
{ //子进程
close(fd[1]); //子进程关闭读端
while(1)
{
read(fd[0], buf, sizeof(buf)); //read 是阻塞的,管道中没数据,等
if(buf[0] == '0')
break;
printf("read is %s\n", buf);
}
}
else if(pid > 0)
{
close(fd[0]);
while(1)
{
scanf("%s", buf);
write(fd[1], buf, sizeof(buf));
if(buf[0] == '0')
break;
}
wait(NULL);
}
}
2
//有名管道,通常在两个不相关的进程间通信(无名管道只能父子进程之间通信)
mkfifo 创建有名管道
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
参数
pathname 管道名
mode 管道的访问权限 (0666)
mkfifo("myfifo", 0666); //一旦执行完mkfifo, 就会新建一个文件, 只不过这个文件创建在内存中, 访问快
打开管道
int fd = open("myfifo", O_RDWR);
读管道
read(fd, buf, sizeof(buf));
写管道
write(fd, buf, sizeof(buf));
关闭管道
close(fd);
read.c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
mkfifo("myfifo", 0666); //可以不执行,如果管道已经存在,不新建
int fd = open("myfifo", O_RDWR);
if(fd > 0)
{
char buf[100] = { 0 };
read(fd, buf, sizeof(buf));
printf("read is %s\n", buf);
close(fd);
}
}
//wrtie.c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
int fd = open("myfifo", O_RDWR);
if(fd > 0)
{
write(fd, "hello", sizeof("hello"));
close(fd);
}
}
gcc read.c -o read
gcc write.c -o write
./read 阻塞
开一个新终端
./write
///练习,修改上面程序,用有名管道完成:
一个进程循环从键盘输入数据写入管道,输入'0',结束,另一个进程循环读出,
///wrtie.c
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
int main()
{
mkfifo("myfifo", 0666); //创建管道, 如果管道不能存在就新建
int fd = open("myfifo", O_RDWR);
if(fd > 0)
{
char buf[100] = { 0 };
while(1)
{
gets(buf);
write(fd, buf, sizeof(buf));
if(buf[0] == '0')
return 0;
}
close(fd);
}
}
/读管道 read.c
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
int main()
{
mkfifo("myfifo", 0666); //创建管道
int fd = open("myfifo", O_RDWR);
if(fd > 0)
{
char buf[100] = { 0 };
while(1)
{
read(fd, buf, sizeof(buf));
if(buf[0] == '0')
{
close(fd);
return 0;
}
printf("read buf is %s\n", buf);
}
}
}
作业:
思维导图
复习: 数据结构, 星期1考试
预习: 信号