1、对比
进程是资源分配的最小单位,线程是程序执行的最小单位
进程拥有自己的独立地址空间,线程间共享进程的所有资源
2、进程
需要头文件 #include<stdlib.h> #include<unistd.h>
2.1 进程的创建
pid_t fork( void);返回值: 若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID;否则,出错返回-1
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main()
{
pid_t p;
p=fork();
if(p<0)
{
printf("error\n");
}
else if(p==0)
{
printf("this is child!\n");
}
else if(p>0)
{
printf("this is father!\n");
}
return 0;
}
2.2 wait()和waitpid()
pid_t wait(int *statloc);
如果成功,wait会返回被收集的子进程的进程ID,如果调用进程没有子进程,调用就会失败,此时wait返回-1
pid_t waitpid(pid_t pid, int *statloc, int options);
作用和wait相同,只不过可以更灵活控制pid和参数
waitpid中pid的含义依据其具体值而变:
pid==-1 等待任何一个子进程,此时waitpid的作用与wait相同
pid >0 等待进程ID与pid值相同的子进程
pid==0 等待与调用者进程组ID相同的任意子进程
pid<-1 等待进程组ID与pid绝对值相等的任意子进程
waitpid的option常量:
WNOHANG waitpid将不阻塞如果指定的pid并未结束
WUNTRACED 如果子进程进入暂停执行情况则马上返回,但结束状态不予以理会。
2.3 exec函数族
#include <unistd.h>
extern char **environ;
int execl(const char *path, const char *arg, ...);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char * const envp[]);
最后一个参数都必须为NULL
调用失败会返回-1
const char *path要写绝对路径,const char *file就不用
例如execlp("ls","ls","-l",NULL);
execl("/bin/ls","ls","-l",NULL);
char *arg[] = {"ls", "-a", NULL}
execv( "/bin/ls",arg);
execvp( "ls",arg);
2.4 system()函数
int system(const char *command)
2.5 给一个例子
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
pid_t p;
p=fork();
if(p<0)
{
perror("create fork\n");
}
else if(p==0)
{
char a[10];
sprintf(a,"%d",getppid());
sleep(3);
execlp("kill","kill","-9",a,NULL);
}
else
{
while(1)
{
printf("this is father!\n");
sleep(1);
}
}
return 0;
}
3、线程
编译时要加上 -lpthread
需要头文件#include<pthread.h>
3.1 线程的创建
int pthread_create(pthread_t *tidp,const pthread_attr_t *attr,(void*)(*start_rtn)(void*),void *arg);
若线程创建成功,则返回0。若线程创建失败,则返回出错编号,并且*thread中的内容是未定义的。
第一个参数为指向线程标识符的指针。
第二个参数用来设置线程属性。
第三个参数是线程运行函数的起始地址。
最后一个参数是运行函数的参数。
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
void *thread1()
{
printf("this is thread1\n");
}
int main()
{
pthread_t pid;
pthread_create(&pid,NULL,thread1,NULL);
pthread_join(pid,NULL);
printf("main down\n");
return 0;
}
3.2 pthread_join()函数
int pthread_join(pthread_t thread, void **retval);
等待一个线程结束,成功返回0,失败返回错误号
3.3 例子
3.3.1传入一个参数并返回
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
void *thread1(void *n)
{
printf("this is thread1\n");
return (void *)(n+1);
}
int main()
{
int a=10,b;
pthread_t pid;
pthread_create(&pid,NULL,thread1,(void *)a);
pthread_join(pid,(void *)&b);
printf("b=%d\n",b);
return 0;
}
3.3.2传入一个结构体并返回
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
struct c{
int a;
char *b;
};
void *thread1(void *n)
{
struct c *temp;
temp=(struct c *)n;
temp->a=11;
printf("temp->a=%d\n",temp->a);
return (void *)temp;
}
int main()
{
struct c *p;
pthread_t pid;
p=(struct c*)malloc(sizeof(struct c));
p->a=10;
p->b="abc";
printf("p->a=%d\n",p->a);
pthread_create(&pid,NULL,thread1,(void *)p);
pthread_join(pid,(void *)&p);
printf("p->a=%d\n",p->a);
return 0;
}
3.3.3传入一个字符串并返回
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
void *thread1(void *b)
{
char *c=(char *)b;
return (void *)c;
}
int main()
{
pthread_t p;
char a[10]="abc";
char *d;
pthread_create(&p,NULL,thread1,(void *)a);
pthread_join(p,(void *)&d);
fputs(d,stdout);
return 0;
}