目录
1.使用GCC
(1)参数
gcc test.c -o tested
./tested
(2)自定义头文件
gcc testf.c -o test -I fdhead
-I:指定头文件所在目录,不指定参数将编译出错
#include <stdio.h>
#include "math.h"
void main()
{
int x=2,y=4;
printf("please input two numbers:\n");
//scanf("%d,%d",&x,&y);
printf("x*y=%d\n",Fmulitply(x,y));
printf("x! is %f\n",Ffactorial(x));
printf("y! is %f\n",Ffactorial(y));
}
int Fmulitply(int x, int y)
{
int z;
z=x*y;
return z;
}//Fmulitply
float Ffactorial(int t)
{
if (t==1)
return 1;
else
return (float)t*Ffactorial(t-1);
}//Ffactorial
(3)makefile脚本
vi makefile
test:test.c test.h (目标文件:依赖文件)
gcc test.c –o test (达成目标使用的命令,句子前有一个tab)
make
或 make test (目标名test与makefile中的要一致)
myfile:
testf2 : testf.c math.h
gcc testf.c -o testf2
cls :
rm testf2
除非特殊指定cls,否则只执行第一个,也就是testf2
(4)gdb调试
2.进程
(1)新建进程:fork()
fork():一次克隆,两个返回值
父进程返回子进程号,子进程返回0
例:如下图所示,应有几个进程?
4个:父,大儿子,二儿子,孙子
根据pid1和pid2的值可以判断出他们的身份
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void){
pid_t pid,pid2;
char *message;
int x;
pid = fork();
pid2 = fork();
if (pid < 0)
{ perror("fork failed");
exit(1); }
if (pid == 0 && pid2 > 0)
{ message = "This is the child1\n";
x = 10; }
else if (pid > 0 && pid2 == 0)
{ message = "This is the child2\n";//父亲第二次克隆孩子
x = 20; }
else if (pid == 0 && pid2 == 0)
{ message = "This is the child1-child\n";
x = 30; }
else
{ message = "This is the parent\n";
x = 0; }
printf("%s I'm %d, x=%d,my father is:%d\n",message,x,getpid(),getppid());
return 0;
}//main
(2)执行:exec
exec是一个函数族,有很多函数,但最后都是下面这个函数执行。
例:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void){
pid_t a;
a = fork();
if (a < 0) {
perror("fork failed");
exit(1); }
if (a == 0) {
printf("child come \n");
execlp ("ps" ,"ps",NULL);
execlp ("ls" ,"ls","-al","/etc/passwd ",NULL);
printf("child exit\n");
return 1; } //if
else {
wait(NULL);
printf("father exit\n");}//else
return 0;
}//main
execlp ("ps" ,"ps",NULL);
execlp ("ls" ,"ls","-al","/etc/passwd ",NULL);执行第一行时代码就被新的覆盖了,所以不会再执行第二行。
只有exec调用失败返回-1,其后的代码才有可能得到执行。
(3)消亡:exit()
程序执行结束或调用exit后并不是马上消失,而是变为僵死状态
想要观察到孩子的僵死态,需要让父亲睡着,否则先祖会来给孩子收尸
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void){
pid_t pid;
char *message;
int x;
pid = fork();
if (pid < 0)
{ perror("fork failed");
exit(1); }
if (pid == 0)
{ message = "This is the child\n";
x = 0; }
else
{ message = "This is the parent\n";
x = 10;
sleep(10); }
printf("%s I'm %d, x=%d,my father is:%d\n",message,x,getpid(),getppid());
return 0;
}//main
&使进程后台执行
22342就是僵尸进程
(4)阻塞:wait()
使调用它的进程等待,进入阻塞状态
子进程死亡会唤醒阻塞的父进程
include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(){
pid_t pc1,pc2,pw1,pw2;
pc1=fork();
pc2=fork();
if (pc1>0 && pc2>0) { //*父进程
pw1=wait(NULL);
pw2=wait(NULL);
printf("***Catch a dead child process with pid: %d\n",pw1);
printf("***Catch a dead child process with pid: %d\n",pw2);
printf("***I'M %d,THE MAIN PROCESS LEAVE!\n",getpid()); }//if
if (pc1==0&&pc2>0) { //*大儿子
printf("===I'M the first child PID:%d,my father is:%d\n",getpid(),getppid());
sleep(10); } //if
if (pc1>0&&pc2==0) //*二儿子
printf("===I'M the 2nd child PID:%d,my father is:%d,i don't sleep.\n",getpid(),getppid());
if (pc1==0&&pc2==0) //*孙进程
printf("I'M grandson PID:%d,my father is:%d,no one is waiting for me.\n",getpid(),getppid());
exit(0);
} //main
创建出4个进程后,父亲阻塞
大儿子输出以后,沉睡10s
二儿子输出然后死亡,唤醒父亲一次
孙子输出然后死亡,但是唤醒不了大儿子,因为大儿子是sleep而不是wait
直到10s后大儿子死亡,父亲才被真正唤醒,输出三句话。
3.线程
由于pthread库不是Linux系统默认的库,需要使用库libpthread.a,所以,编译连接时,命令后需加“-l pthread” 参数帮助编译器找到相应的库。
需要注意:线程可以创建新线程,两个线程是等同层次,不存在亲缘关系。
#include <othread.h>
创建线程函数:pthread_create
int pthread_create(pthread_t* tid,const pthread_attr_t* attr,void* (*start_rtn),void *restrict arg);
成功返回0,失败返回错误号
(1)tid:事先创建好的pthread_t类型的线程标识符,整型。成功时tid指向的内存单元被设置为新创建线程的线程ID。
(2)attr:设置线程属性,通常设为NULL。
(3)start_rtn:新创建的线程从此函数开始运行,无参数时设为NULL。
(4)arg:start_rtn函数的参数,无参数时设为NULL,有参数时输入参数的地址。当多于一个参数时使用结构体传入。
终止线程: pthread_cancel、pthread_exit
void pthread_exit(void *retval):retval表示线程退出状态,通常传NULL,终止自己。
int pthread_cancel(pthread_t tid):终止同进程中的另一个线程,tid是线程标识符。成功返回0,失败返回错误号
线程等待:pthread_join
pthread_join(tid,void * *retval):主线程等待子线程tid的终止,reval根据终止状态返回不同值。
return返回:reval为返回值
pthread_cancel终止:reval为PTHREAD_CANCEL常量
pthread_exit终止:pthread_exit的参数
对终止状态不感兴趣传NULL
(1)共同操作共享变量
例1:
①线程共享资源: 共同影响进程的message变量
②并发执行: 交替输出message当前的值
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
//#include <pthread>
//例5-10
char message[50] = "Hello World";
//线程共享,初值为helloworld
void *thread_function(void *arg){
int k=0;
printf("===Thread_function1 is running. Argument was %s\n", (char *)arg);
//注意此处循环设置过少会使线程执行时间短,测试体现不出并发效果
for(k=0;k<10;k++) {
sleep(rand()%3);
strcpy(message, "THREAD!"); }//for
pthread_exit("===Thank you for your CPU time!"); }
void *thread_function2(void *arg){
int k=0;
printf("===Thread_function2 is running. Argument was %s\n", (char *)arg);
for(k=0;k<10;k++) {
sleep(rand()%3);
strcpy(message,"ANOTHER THREAD!"); }//for
pthread_exit("===Thank you for your CPU time!"); }
int main(){
int res,k;
pthread_t thread1;
pthread_t thread2;
void *thread_result;
res = pthread_create(&thread1, NULL, thread_function, (void *)message);
res = pthread_create(&thread2, NULL, thread_function2, (void *)message);
for(k=0;k<20;k++) {
sleep(1);
printf("Message is now %s\n", message);
} //for
exit(EXIT_FAILURE);
}
例2:两个线程对共享的进程变量做加1操作,结果加和是错的。
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
long x=0,y=0,z=0;
void *thread_function1()
{
printf("thread_function1 is running \n");
while(1)
{
x++;
z++;
}
pthread_exit("thank you for your cpu time");
}
void *thread_function2()
{
printf("thread_function2 is running \n");
while(1)
{
y++;
z++;
}
pthread_exit("thank you for your cpu time");
}
int main(){
int res;
pthread_t thread1;
pthread_t thread2;
res=pthread_create(&thread1,NULL,thread_function1,NULL);//创建子线程
res=pthread_create(&thread2,NULL,thread_function2,NULL);
sleep(1);
printf(" x= %d\n",x);
printf(" y= %d\n",y);
printf(" x+y = %d\n",x+y);
printf(" z= %d\n",z);
exit(EXIT_FAILURE);
}
按理说x+y=z,但是结果不对。
线程对共享变量的处理应互斥,否则会出现线程不安全问题
(2)执行顺序控制
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
//例5-11
char message[50] = "Hello World";
void *thread_function(void *arg) {
printf("===CHILD run and want to sleep(5). message NOW is %s\n", (char *)arg);
sleep(5);
strcpy(message, "HELLO FATHER!");
pthread_exit("===Thank you for your CPU time!");
}
int main(){
int res;
pthread_t threadCH;
void *thread_result;
res=pthread_create(&threadCH,NULL,thread_function,(void *)message);
if(res!=0){
perror("thread creation failed");
exit(EXIT_FAILURE);
}
printf("Main thread is waiting for thread to finish by join \n");
res=pthread_join(threadCH,&thread_result);
if(res!=0){
perror("thread join failed\n");
exit(EXIT_FAILURE);
}
printf("child thread returned %s\n",(char *)thread_result);
printf("message now is %s\n",message);
exit(EXIT_FAILURE);
}