实验一:处理机调度

实验一:处理机调度

  1. 在root下建立一个文件夹名字叫CProgram,进入CProgram文件夹。

建立文件夹,使用命令:

root@kali:~# mkdir CProgram

如果要删除,使用命令:

root@kali:~# rm -rf 文件夹名

进入该文件夹,使用命令:

root@kali:~# cd CProgram

rm 命令可以删除一个目录中的一个或多个文件或目录,也可以将某个目录及其下属的所有文件及其子目录均删除掉。使用一定要谨慎。

  1. 试试新建一个C程序,并实现helloword功能。

使用命令:新建文件、编译文件、运行文件

root@kali:~/CProgram# gedit helloworld.c

root@kali:~/CProgram# gcc helloworld.c -o helloworld

生成可执行文件helloworld。

root@kali:~/CProgram# ./helloworld


3.fork函数的使用

fork()是创建进程函数。

 一个进程,包括代码、数据和分配给进程的资源。fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。

一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。

3.1 编写程序forkPID.c

程序代码:

#include <stdio.h>

#include <sys/types.h>

#include <unistd.h>

int main()

{

pid_t pid;

printf("Start of fork testing\n");

pid=fork();

if(pid>0)

printf("In parent\n");

else

printf("In child\n");

printf("Return of fork sucess: pid:%d\n",pid);

return 0;

}

输出效果:

Start of fork testing

In parent

Return of fork sucess: pid:2575

In child

Return of fork sucess: pid:0

fork函数被调用一次,却能够返回两次,它可能有三种不同的返回值:
    1)在父进程中,fork返回新创建子进程的进程ID;
    2)在子进程中,fork返回0;
    3)如果出现错误,fork返回一个负值;

使用命令:新建文件、编译文件、运行文件

root@kali:~/CProgram# gedit forkPID.c

root@kali:~/CProgram# gcc forkPID.c -o forkPID

root@kali:~/CProgram# ./forkPID

3.2编写程序forkMoreTest.c

#include <stdio.h>

#include <sys/types.h>

#include <unistd.h>

int main()

{

pid_t pid;

int i;

printf("Start of fork testing\n");

pid=fork();

if(pid>0)

{

printf("In parent\n");

i=5;

}

else

{

printf("In child\n");

i=10;

}

printf("Return of fork sucess: pid:%d\n",pid);

printf("The value of i is :%d\n",i);

return 0;

}

输出效果:

Start of fork testing

In parent

Return of fork sucess: pid:4922

The value of i is :5

In child

Return of fork sucess: pid:0

The value of i is :10

Start of fork testing

In parent

In child

Return of fork sucess: pid:0

The value of i is :10

Return of fork sucess: pid:4942

The value of i is :5

Start of fork testing

In parent

Return of fork sucess: pid:4945

In child

The value of i is :5

Return of fork sucess: pid:0

The value of i is :10

提问:

比较三次运行效果的异同,试回答为什么同样的代码会有产生不同的运行效果。

  1. 创建线程

线程可以在进程执行期间的任意时刻被创建,且线程的数量没有必要事先指定,这样的线程称为动态线程。

线程可以用pthread_create动态创建。函数pthread_create能创建进程,并将它放入就绪队列。

pthread_create包括四个参数:线程ID、线程属性、线程运行的函数、函数的参数。示例代码如下是:

#include <stddef.h>

#include <stdio.h>

#include <unistd.h>

#include <pthread.h>

void print_message(char* ptr);

int main()

{

pthread_t thread1,thread2;

char *msg1="Hello\n";

char *msg2="World\n";

pthread_create(&thread1,NULL,(void *)(&print_message),(void *)msg1);

pthread_create(&thread2,NULL,(void *)(&print_message),(void *)msg2);

sleep(1);

return 0;

}

void print_message(char* ptr )

{

int retval;

printf("Thread ID %lx\n",pthread_self());

printf("%s\n",ptr);

pthread_exit(&retval);

return;

}

输出效果:

Thread ID 7fa265a77700

Hello

Thread ID 7fa265276700

World

使用命令:新建文件、编译文件、运行文件

root@kali:~/CProgram# gedit threadID.c

root@kali:~/CProgram#gcc -pthread threadID.c -o threadID

root@kali:~/CProgram# ./threadID

提问:

代码sleep(1)的作用是什么?不用会怎么样?

  1. 挂起线程

函数pthread_join用于挂起当前线程直至指定线程终止。函数原型:

int thread_join(pthread_t th, void **thread_return)

参数th是一个线程标识符,用于指定等待其终止的线程。参数thread_return用于存放其他线程的返回值。如果执行成功,那么参数th的返回值将保存在有参数thread_return指向的地址中,函数返回0,否则返回一个非零值。

代码中如果没有thread_join;主线程会很快结束从而使整个进程结束,从而使创建的线程没有机会开始执行就结束了。加入thread_join后,主线程会一直等待直到等待的线程结束自己才结束,使创建的线程有机会执行。

示例代码如下:

#include <stddef.h>

#include <stdio.h>

#include <unistd.h>

#include <pthread.h>

void print_msg(char *ptr);

int main()

{

pthread_t thread1,thread2;

int i,j;

void *retval;

char *msg1="Hello\n";

char *msg2="World\n";

pthread_create(&thread1,NULL,(void*)(&print_msg),(void*)msg1);

pthread_create(&thread2,NULL,(void*)(&print_msg),(void*)msg2);

pthread_join(thread1,&retval);

pthread_join(thread2,&retval);

return 0;

}

void print_msg(char *ptr)

{

int i;

for(i=0;i<10;i++)

printf("%s",ptr);

return;

}

试一试:

删除代码1、2,或者删除1和2的区别是什么?

(1)pthread_create(&thread1,NULL,(void*)(&print_msg),(void*)msg1);

(2)pthread_create(&thread2,NULL,(void*)(&print_msg),(void*)msg2);

使用命令:

root@kali:~/CProgram# gcc pthread_join.c -o pthread_join -lpthread

root@kali:~/CProgram# ./pthread_join

输出效果:

Hello

Hello

Hello

Hello

Hello

Hello

Hello

Hello

Hello

Hello

World

World

World

World

World

World

World

World

World

World

  1. 线程同步-1,单个缓冲区,生产者消费者/读写问题

POSIX提供了两种类型的同步机制,互斥锁mutex和条件变量(condition variable).

互斥锁是一个简单的锁定命令,它可以用来锁定对临界资源的访问。

示例代码:

#include <stddef.h>

#include <stdio.h>

#include <unistd.h>

#include <pthread.h>

#define FALSE 0

#define TRUE 1

void readfun();

void writefun();

char buffer[256]={0};

int buffer_has_item=0;

int retflag=FALSE;

pthread_mutex_t mutex;//定义了一个互斥锁

int main()

{

pthread_t reader;

pthread_mutex_init(&mutex,NULL);//初始化互斥锁

pthread_create(&reader,NULL,(void*)&readfun,NULL);//创建读者线程

writefun();//写者在主进程中

}

void readfun()

{

while(1)

{

if(retflag)

return;

pthread_mutex_lock(&mutex);//锁定临界区

if(buffer_has_item==1)

{

printf("I'm reading:%s",buffer);

buffer_has_item=0;

}

pthread_mutex_unlock(&mutex);//释放临界区

}

return;

}

void writefun()

{

int i=0;

while(1)

{

if(i==10)

{

retflag=TRUE;

return;

}

pthread_mutex_lock(&mutex);//锁定临界区

if(buffer_has_item==0)

{

printf("I'm writing\n");

sprintf(buffer,"This is %d\n",i++);

buffer_has_item=1;

}

pthread_mutex_unlock(&mutex);//释放临界区

}

return;

}

使用命令:

root@kali:~/CProgram# gedit mutex.c

root@kali:~/CProgram# gcc mutex.c -o mutex -lpthread

root@kali:~/CProgram# ./mutex

  1. 线程同步-2,多个缓冲区,生产者消费者/读写问题

在程序中使用互斥锁虽然可以解决一些资源竞争的问题,但是互斥锁只有两种状态,这使得它的用处非常有限。

条件变量是对互斥锁的补充,它允许线程阻塞并等待另一个线程发送的信号。当收到信号时,阻塞的线程被唤醒并试图锁定预支相关的互斥锁。

示例代码:

#include <stdio.h>

#include <pthread.h>

#define BUFFERA_SIZE 4

#define OVER (-1)

struct producers

{

int buffer[BUFFERA_SIZE];

pthread_mutex_t lock;

int readpos,writepos;

pthread_cond_t notempty;

pthread_cond_t notfull;

};

void init(struct producers *b)

{

pthread_mutex_init(&b->lock,NULL);

pthread_cond_init(&b->notempty,NULL);

pthread_cond_init(&b->notfull,NULL);

b->readpos=0;

b->writepos=0;

}

void put(struct producers *b, int data)

{

pthread_mutex_lock(&b->lock);

while((b->writepos+1)%BUFFERA_SIZE==b->readpos)

pthread_cond_wait(&b->notfull,&b->lock);

b->buffer[b->writepos]=data;

b->writepos++;

if(b->writepos>=BUFFERA_SIZE)

b->writepos=0;

pthread_cond_signal(&b->notempty);

pthread_mutex_unlock(&b->lock);

return;

}

int get(struct producers *b)

{

int data;

pthread_mutex_lock(&b->lock);

while(b->writepos==b->readpos)

pthread_cond_wait(&b->notempty,&b->lock);

data=b->buffer[b->readpos];

b->readpos++;

if(b->readpos>=BUFFERA_SIZE)

b->readpos=0;

pthread_cond_signal(&b->notfull);

pthread_mutex_unlock(&b->lock);

return data;

}

struct producers buffer;

void *producer(void *data)

{

int n;

for(n=0;n<10;n++)

{

printf("Producer:%d-->\n",n);

put(&buffer,n);

}

put(&buffer,OVER);

return NULL;

}

void *consumer(void *data)

{

int d;

while(1)

{

d=get(&buffer);

if(d==OVER) break;

printf("Consumer:-->%d\n",d);

}

return NULL;

}

int main()

{

pthread_t tha,thb;

void *retval;

init(&buffer);

pthread_create(&tha,NULL,producer,0);

pthread_create(&thb,NULL,consumer,0);

pthread_join(tha,&retval);

pthread_join(thb,&retval);

return 0;

}

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值