webdancer's Blog

[翻译]POSIX 线程编程

文章原文:POSIX Threads Programming

作者: Blaise Barney, Lawrence Livermore National Laboratory

地址:https://computing.llnl.gov/tutorials/pthreads/#PthreadsAPI

翻译:webdancer(翻译的不好,勿喷,O(∩_∩)O~)

=================================================

  1. 概要
  2. Pthreads总览
  1. 什么是线程?
  2. 什么是Pthreads?
  3. 为什么有Pthreads?
  4. 设计线程程序

继续阅读

os实验--进程的调度

Linux系统中,进程的调度策略其实是一个比较困难的问题,实验指导书上的只是很不全面,而且模棱两可。现在只能大致了解一下: 通用Linux系统支持实时和非实时两种进程,实时进程相对于普通进程具有绝对的优先级。 通用Linux系统支持实时和非实时两种进程,实时进程相对于普通进程具有绝对的优先级。对应地,实时进程采用SCHED_FIFO或者SCHED_RR调度策略,普通的进程采用SCHED_OTHER调度策略。

优先级:

非实时进程有两种优先级,一种是静态优先级,另一种是动态优先级。实时进程又增加了第三种优先级,实时优先级。优先级是一些简单的整数,它代表了为决定应该允许哪一个进程使用 CPU 的资源时判断方便而赋予进程的权值——优先级越高,它得到 CPU 时间的机会也就越大:
1 .静态优先级——被称为“静态”是因为它不随时间而改变,只能由用户进行修改。它指明了在被迫和其它进程竞争 CPU 之前该进程所应该被允许的时间片的最大(但是也可能由于其它原因,在该时间片耗尽之前进程就被迫交出了 CPU。)值。
2.动态优先级——只要进程拥有 CPU,它就随着时间不断减小;当它小于 0 时,标记进程重新调度。它指明了在这个时间片中所剩余的时间量。
3.实时优先级——指明这个进程自动把 CPU 交给哪一个其它进程:较高权值的进程总是优先于较低权值的进程。因为如果一个进程不是实时进程,其优先级就是 0,所以实时进程总是优先于非实时进程的。
(这并不完全正确;如同后面论述的一样,实时进程也会明确地交出 CPU,而在等待 I/O 时也会被迫交出 CPU。前面的描述
仅限于能够交付 CPU 运行的进程).
 

 

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<signal.h>
#include<sched.h>
#include<sys/times.h>
#include<sys/resource.h>
typedef void (*sighandler_t)(int);
void sigcon(){
	pid_t pi=getpid();
        int pj=getpriority(PRIO_PROCESS,pi);
        setpriority(PRIO_PROCESS,pi,pj+1);
        printf("the  pid is : %d ,the priority is %d,after SIGINT the priority is : %d\n",pi,pj,pj+1);
}
void sigcon1(){
        pid_t pi=getpid();
	int pj=getpriority(PRIO_PROCESS,pi);
	setpriority(PRIO_PROCESS,pi,pj-1);
	printf("the  pid is : %d ,the priority is %d,after SIGTSTP the priority is : %d\n",pi,pj,pj-1);
}
int main(){
	pid_t p0;
	signal(SIGINT,(sighandler_t)sigcon);
	signal(SIGTSTP,(sighandler_t)sigcon1);
	int index;
	if((p0=fork())<0){
		perror("error!");
		exit(0);
	}
	else if(p0==0){
		for(index=0;index<4;index++){
		pid_t cp=getpid();
		int chpriority=getpriority(PRIO_PROCESS,cp);
		int schednum=sched_getscheduler(cp);
		printf("the child pid is : %d , the priority is : %d , the sched is : %d \n",cp,chpriority,schednum);
		kill(cp,SIGINT);
//                kill(cp,SIGTSTP);
		}
	}
	else{
		int in;
		for(in=0;in<4;in++){
		pid_t pp=getpid();
		int ppriority=getpriority(PRIO_PROCESS,pp);
		int pschednum=sched_getscheduler(pp);
		printf("the parent pid is : %d , the priority is : %d , the sched is : %d \n",pp,ppriority,pschednum);
		kill(pp,SIGINT);
        //	kill(pp,SIGTSTP);
		}
	}
	return 0;
}			 

os实验--线程的创建

Linux 利用了特有的内核函数__clone 实现了一个叫 phread 的线程库,__clone是 fork 函数的替代函数,通过更多的控制父子进程共享哪些资源而实现了线程。Pthread 是一个标准化模型,用它可把一个程序分成一组能够并发执行的多个任务。phread 线程库是 POSIX 线程标准的实现,它提供了 C 函数的线程调用接口和数据结构。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
int  tjobs0(int  );
int  tjobs1(int  );
pthread_t thr0,thr1;
int num0,num1;
int main(int argc,char * argv[]){
	int result;
	int ret0,ret1;
	int x,y;
	printf("input the x and y\n");
	printf("input x: ");
        scanf("%d",&x);
	printf("input y: ");
	scanf("%d",&y);
	ret0=pthread_create(&thr0,NULL,(void*)tjobs0,(void * )x);
	if(ret0<0){
		perror("error!");
		exit(0);
	}
        ret1=pthread_create(&thr1,NULL,(void *)tjobs1,(void *)y);
        if(ret1<0){
	 perror("error!");
	 exit(0);	
	}
	pthread_join(thr0,NULL);
	pthread_join(thr1,NULL);
	result=num0+num1;
	printf("the result is %d\n",result);
	return 0;
	}
int  tjobs0(int  i){
	if(i==1)
		num0=1;
	else if(i>1){
		num0=tjobs0(i-1)*i;
		i--;
	}
	return num0;
}
int  tjobs1(int  j){
	if(j==1||j==2)
		num1=1;
	else if(j>2){
		num1=tjobs1(j-1)+tjobs1(j-2);
		j--;
	}
	return num1; 
}

gcc :gcc是GNU计划的c /c++的编译器。

gcc的用法(详细:info gcc ):

-E: 预处理。

-S:z只编译,不汇编,生成汇编代码。

-c:编译或者汇编,但不链接。

-o:输出到指定文件。

 

os实验1 ——进程控制

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<signal.h>
#include<stdlib.h>
typedef  void (*sighandler_t) (int);
void sincon()
{
}
int main()
{
    pid_t p0;
    int sta0,sta1;
    signal(SIGINT,(sighandler_t)sincon);
    while(1)
    {
        if((p0=fork())<0)
        {
            perror("error!fork first child");
            exit(0);
        }
        else if(p0==0)
        {
            pause();
            sta0=execlp("/bin/ls","ls",NULL);
            exit(0);
        }
        else
        {
            pid_t p1;
            if((p1=fork())<0)
            {
                perror("error!fork second child");
                exit(0);
            }
            else if(p1==0)
            {
                printf("exe the second child\n");
                sta1=execlp("/bin/ps","ps",NULL);
                exit(0);
            }
            else
            {
                if(waitpid(p1,&sta1,0)!=p1)
                    perror("error!");
                if((kill(p0,SIGINT))>=0)
                    printf("wake up first child\n");
                sleep(3);
            }
        }
    }
    return 0;
}

 

 

fork函数二三事

1.fork函数的基本功能

在linux中,只有一个函数可以创建子进程:fork。

#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);

由fork创建的新进程被称为子进程( child process)。该函数被调用一次,但返回两次。两次返回的区别是子进程的返回值是0,而父进程的返回值则是新子进程的进程I D。将子进程I D返回给父进程的理由是:因为一个进程的子进程可以多于一个,所以没有一个函数使一个进程可以获得其所有子进程的进程I D。fork使子进程得到返回值0的理由是:一个进程只会有一个父进程,所以子进程总是可以调用getppid以获得其父进程的进程ID(进程ID 0总是由交换进程使用,所以一个子进程的进程ID不可能为0 )。

2.CoW(Copy on Write)

CoW是现代操作系统中的一个很重要的策略,在fork中也使用了。看一下下面这个例子。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
int main(){
          int i;
          pid_t p0;
          if((p0=fork())<0){
                 perror("error!");
                 exit(0);
}
         else if(p0==0){
                 i=getpid();
                 printf("i is %d the i address is %p in the child\n",i,&i);
         }
         else {
                 i=getpid();
                 printf("i is %d the i address is %p in the parent\n",i,&i);
         }
         return 0;
 }

 运行的结果:

i is 3132 the i address is 0xbf8147e8 in the parent
i is 3133 the i address is 0xbf8147e8 in the child

为什么会有相同的i地址呢?不是当fork()产生子进程的时候,会copy吗?
因为现代的OS基本采用了COW技术。父子进程共享数据和堆。

3.缓冲问题

在这里http://coolshell.cn/articles/7965.html看到了一个很有趣的问题,代码如下:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
 
int main(void)
{
   int i;
   for(i=0; i<2; i++){
      fork();
      printf("-");
   }
 
   return 0;
}

问一下:上面到底会输出几个‘-'。答案不是六个,而是八个。原因就是因为父进程的buffer也被子进程继承了。详细的分析可以参照Coolshell的这篇文章http://coolshell.cn/articles/7965.html。

 

 

 




Host by is-Programmer.com | Power by Chito 1.3.3 beta | © 2007 LinuxGem | Design by Matthew "Agent Spork" McGee