named pipes

advertisement

2.3 InterProcess

Communication (IPC)

Part C

IPC methods

1.

2.

3.

4.

5.

Signals

Mutex (MUTual EXclusion)

Semaphores

Shared memory

Memory mapped files

6.

7.

8.

9.

Pipes & named pipes

Sockets

Message queues

MPI (Message Passing Interface)

10.

Barriers

Pipes and named pipes

Pipes

Cmd1’s stdout becomes

Cmd2’s stdin.

one direction only

More Pipes

Too many pipes?!

// Excerpt from "Linux Programmer's Guide - Chapter 6."

// (C)opyright 1994-1995, Scott Burkett

#include <stdio.h>

#include <unistd.h>

#include <sys/types.h>

Pipes via pipe()

(child writing to parent) int main ( int argc, char* argv[] ) { int fd[2] , nbytes; pid_t childpid; char string[] = "Hello, world!\n", readbuffer[80]; pipe( fd ); //fd[0] is opened for reading (input side);

// fd[1] is opened for writing (output side).

// Excerpt from "Linux Programmer's Guide - Chapter 6."

// (C)opyright 1994-1995, Scott Burkett

#include <stdio.h>

#include <unistd.h>

#include <sys/types.h>

Pipes via pipe()

(child writing to parent) int main ( int argc, char* argv[] ) { int fd[2], nbytes; pid_t childpid; char string[] = "Hello, world!\n", readbuffer[80]; pipe( fd ); //fd[0] is opened for reading (input side);

// fd[1] is opened for writing (output side).

if ( (childpid = fork()) == -1 ) { perror( "fork" ); exit( 1 );

}

}

// Excerpt from "Linux Programmer's Guide - Chapter 6."

// (C)opyright 1994-1995, Scott Burkett

#include <stdio.h>

#include <unistd.h>

#include <sys/types.h> int main ( int argc, char* argv[] ) {

Pipes via pipe()

(child writing to parent) int fd[2], nbytes; pid_t childpid; char string[] = "Hello, world!\n", readbuffer[80]; pipe( fd ); //fd[0] is opened for reading (input side);

// fd[1] is opened for writing (output side).

if ((childpid = fork()) == -1) { perror( "fork" ); exit( 1 );

} if (childpid == 0) { //child process closes input side of pipe, & writes close( fd[0] );

/* Send "string" through the output side of pipe */

} write( fd[1], string, (strlen(string)+1) );

} else { //parent process closes output side of pipe, & reads close( fd[1] );

/* Read in a string from the pipe */ nbytes = read( fd[0], readbuffer, sizeof(readbuffer) ); printf( "parent: received string: %s", readbuffer ); return 0;

// Excerpt from "Linux Programmer's Guide - Chapter 6."

// (C)opyright 1994-1995, Scott Burkett

#include <stdio.h>

#include <unistd.h>

#include <sys/types.h>

Pipes via pipe()

(child writing to parent) int main ( int argc, char* argv[] ) { int fd[2], nbytes; pid_t childpid; char string[] = "Hello, world!\n", readbuffer[80]; pipe( fd ); //fd[0] is opened for reading (input side);

// fd[1] is opened for writing (output side).

} if ((childpid = fork()) == -1) { perror( "fork" ); exit( 1 );

} if (childpid == 0) { //child process closes input side of pipe, & writes close( fd[0] );

/* Send "string" through the output side of pipe */ write( fd[1], string, (strlen(string)+1) );

} else { //parent process closes output side of pipe, & reads close( fd[1] );

/* Read in a string from the pipe */ nbytes = read( fd[0], readbuffer, sizeof(readbuffer) ); printf( "parent: received string: %s", readbuffer );

} return 0;

This is child writing to parent.

How can we change it to be parent to child?

// Excerpt from "Linux Programmer's Guide - Chapter 6."

// (C)opyright 1994-1995, Scott Burkett

#include <stdio.h>

#include <unistd.h>

#include <sys/types.h>

Pipes via pipe()

(parent writing to child) int main ( int argc, char* argv[] ) { int fd[2], nbytes; pid_t childpid; char string[] = "Hello, world!\n", readbuffer[80]; pipe( fd ); //fd[0] is opened for reading (input side);

// fd[1] is opened for writing (output side).

if ((childpid = fork()) == -1) { perror( "fork" ); exit( 1 );

} if (childpid != 0) { //parent process closes input side of pipe, & writes close( fd[0] );

/* Send "string" through the output side of pipe */

} write( fd[1], string, (strlen(string)+1) );

} else { //child process closes output side of pipe, & reads close( fd[1] );

/* Read in a string from the pipe */ nbytes = read( fd[0], readbuffer, sizeof(readbuffer) ); printf( "parent: received string: %s", readbuffer );

} return 0;

That was easy!

PIPES BETWEEN PROCESSES

(USING POPEN)

Problem

I need to sort data but it’s complicated so I can’t use the regular sort function.

There is a program called for me.

sort

that can do it

But how can I use it?

}

// Excerpt from "Linux Programmer's Guide - Chapter 6."

// (C)opyright 1994-1995, Scott Burkett

#include <stdio.h>

#define MAXSTRS 5 int main ( int argc, char* argv[] ) {

FILE* pipe_fp;

Pipes via popen()

(pipes to/from processes) char* strings[ MAXSTRS ] = { "echo", "bravo", "alpha", "charlie", "delta" };

/* Create one way pipeline with call to popen() */ if ( ( pipe_fp = popen("sort", "w")) == NULL) { perror( "popen" ); exit( 1 );

Can be “w” or “r”.

}

/* Processing loop */

Any valid shell command.

for (int cntr=0; cntr<MAXSTRS; cntr++) { fputs( strings[cntr], pipe_fp ); fputc( '\n', pipe_fp );

}

/* Close the pipe */ pclose( pipe_fp ); return 0;

}

// Excerpt from "Linux Programmer's Guide - Chapter 6."

// (C)opyright 1994-1995, Scott Burkett

#include <stdio.h>

#define MAXSTRS 5 int main ( int argc, char* argv[] ) {

FILE* pipe_fp;

Pipes via popen()

(pipes to/from processes) char* strings[ MAXSTRS ] = { "echo", "bravo", "alpha", "charlie", "delta" };

/* Create one way pipeline with call to popen() */ if (( pipe_fp = popen("sort", "w")) == NULL) { perror( "popen" ); exit( 1 );

}

/* Processing loop */ for (int cntr=0; cntr<MAXSTRS; cntr++) { fputs( strings[cntr], pipe_fp ); fputc( '\n', pipe_fp );

}

/* Close the pipe */ pclose( pipe_fp ); return 0;

}

// Excerpt from "Linux Programmer's Guide - Chapter 6"

// (C)opyright 1994-1995, Scott Burkett

#include <stdio.h>

#define MAXSTRS 5

Pipes via popen() int main ( int argc, char* argv[] ) {

FILE* pipe_fp; char* strings[ MAXSTRS ] = { "echo", "bravo", "alpha", "charlie", "delta" };

/* Create one way pipeline with call to popen() */ if (( pipe_fp = popen("sort", "w")) == NULL) { perror( "popen" ); exit( 1 );

}

/* Processing loop */ for (int cntr=0; cntr<MAXSTRS; cntr++) { fputs( strings[cntr], pipe_fp ); fputc( '\n', pipe_fp );

}

/* Close the pipe */ pclose( pipe_fp ); return 0;

How would I modify this to obtain the sorted information?

}

// Excerpt from "Linux Programmer's Guide - Chapter 6"

// (C)opyright 1994-1995, Scott Burkett

#include <stdio.h>

#define MAXSTRS 5 int main ( int argc, char* argv[] ) {

FILE* pipe_fp;

Pipes via popen() char* strings[ MAXSTRS ] = { "echo", "bravo", "alpha", "charlie", "delta" };

/* Create one way pipeline with call to popen() */ if (( pipe_fp = popen("sort > junk.dat", "w")) == NULL) { perror( "popen" ); exit( 1 );

}

/* Processing loop */ fputc( '\n', pipe_fp );

}

/* Close the pipe */ pclose( pipe_fp ); return 0;

Any valid shell command.

for (int cntr=0; cntr<MAXSTRS; cntr++) { fputs( strings[cntr], pipe_fp ); How would I modify this to have obtain the sorted information?

This works, but is junk.dat unique?

NAMED PIPES

Named pipes

Named pipes

 Use mkfifo command. (What is a FIFO?)

 Example

► mkfifo mypipe

► ls –l mypipe

p

rw------1 ggrevera ggrevera 0 Oct 5 21:30 mypipe

► ls –l > mypipe

 Hangs! Why?

 Ctrl-c

► ls –l > mypipe &

► cat < mypipe

 Doesn’t hang! Why?

Using a pipe to communicate to a child’s stdin

execlp( "sort", "sort", "-n", NULL ); #include <assert.h>

#include <stdio.h>

#include <stdlib.h>

#include <strings.h>

#include <sys/types.h>

#include <unistd.h> perror( "exec failed." ); //should never get here!

exit( -1 );

} else { //in parent process close( fd[0] ); //close unused side of pipe int main ( int argc, char* argv[] ) { int fd[ 2 ]; pipe( fd ); //fd[0] is opened for reading (input side);

// fd[1] is opened for writing (output side).

pid_t childpid = fork(); assert( childpid != -1 ); if (childpid == 0) { //in child process close( fd[1] ); //MUST close unused side of pipe close( 0 ); //close child's current, default stdin dup( fd[0] ); //duplicate input side of pipe to stdin

//create child process

//execlp( "cat", "cat", NULL );

//execlp( "sort", "sort", NULL );

//write info to pipe char buff[ 256 ]; for (int i=0; i<=10; i++) { sprintf( buff, "%d \n", i ); write( fd[1], buff, strlen(buff) );

}

} close( fd[1] ); //indicates that we are done int status; wait( &status ); //wait for child to finish

} puts( "done." ); return 0; parent’s fd[1] ----> child’s stdin

Named pipes

Named pipes

 Use mkfifo command. (What is a FIFO?)

 Example

► mkfifo mypipe

► ls –l mypipe

p

rw------1 ggrevera ggrevera 0 Oct 5 21:30 mypipe

► ls –l > mypipe

 Hangs! Why?

Because it waits for the reader.

 Ctrl-c

► ls –l > mypipe &

► cat < mypipe

 Doesn’t hang! Why?

Because the reader executes.

 Output on next slide.

Output from named pipe example

► ls –l > mypipe & cat < mypipe total 106412

-rwx-----1 ggrevera ggrevera 14215 Oct 5 20:45 a.out

drwx-----5 ggrevera ggrevera 4096 Feb 3 2006 csc4025 drwx-----4 ggrevera ggrevera 4096 Oct 3 09:59 csc4035

-rw------1 ggrevera ggrevera 194560 Sep 6 12:52 csc4035.tar

-rw------1 ggrevera ggrevera 891 Dec 4 2005 dir.cpp

.

.

.

-rw------1 ggrevera ggrevera 283 Oct 5 20:44 sig.cpp

[1]+ Done ls -l >mypipe

Why did this finish? Because the reader reads everything.

Named pipes (Windows)

CreatePipe

 Creates an anonymous pipe.

CreateNamedPipe

 Creates an instance of a named pipe and returns a handle for subsequent pipe operations. A client process connects to a named pipe by using the CreateFile or CallNamedPipe function.

CallNamedPipe

 Connects to a message-type pipe, writes to and reads from the pipe, and then closes the pipe.

TransactNamedPipe

 Combines the functions that write a message to and read a message from the specified named pipe into a single network operation.

Sockets

Sockets

Communications between systems across the network!

Sockets – client-side

Steps:

1.

socket()

 creates an endpoint for communication and returns a descriptor

2.

connect()

 attempts to make a connection to another socket

3.

call read() and/or write()

 similar to an ordinary file

Sockets

Grand list of standard port numbers: http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers

Demo

Run cmd (the Windows command prompt).

telnet www.google.com 80

get<enter>

GET<enter>

Note: HTTP (HyperText Transfer Protocol) is case sensitive!

SOCKETS – CLIENT SIDE

//----------------------------------------------------------------------

//----------------------------------------------------------------------

#include <stdio.h>

#include <stdlib.h>

#include <strings.h>

#include <sys/socket.h>

Sockets – client-side

(writes a message and reads a response)

#include <netinet/in.h>

#include <unistd.h>

#include <netdb.h>

#include <sys/types.h>

//---------------------------------------------------------------------static void error ( char* msg ) { perror( msg ); exit( 0 );

}

//---------------------------------------------------------------------int main ( int argc, char* argv[] ) { if (argc < 3) { fprintf( stderr, "usage: %s hostname port \n", argv[0] ); exit( 0 );

}

//get port number from command line int portno = atoi( argv[2] );

...

//create an endpoint for communication int sockfd = socket( AF_INET, SOCK_STREAM, 0 ); if (sockfd < 0) error( "ERROR opening socket" );

.

.

.

Sockets – client-side

//get host name from command line struct hostent* server = gethostbyname( argv[1] ); if (server == NULL) { fprintf( stderr, "ERROR, no such host \n" ); exit( 0 );

}

.

.

.

struct sockaddr_in serv_addr; memset( &serv_addr, sizeof(serv_addr), 0 ); serv_addr.sin_family = AF_INET; memcpy( &serv_addr.sin_addr.s_addr, server->h_addr, server->h_length ); serv_addr.sin_port = htons( portno ); if ( connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr) ) < 0) error( "ERROR connecting" );

Mention memset and memcpy.

.

.

.

Sockets – client-side printf( "Please enter the message: " ); char buffer[256]; memset( buffer, sizeof(buffer), 0 ); fgets( buffer, sizeof(buffer)-1, stdin );

//fgets includes \n, so we'll remove it (if necessary) if (strlen(buffer) > 0 && buffer[strlen(buffer)-1] == '\n') buffer[ strlen(buffer)-1 ] = 0; int n = write( sockfd, buffer, strlen(buffer)+1 ); //+1 to include \0 if (n < 0) error( "ERROR writing to socket" ); memset( buffer, sizeof(buffer), 0 ); n = read( sockfd, buffer, sizeof(buffer)-1 ); if (n < 0) error( "ERROR reading from socket" ); printf( "response: %s \n", buffer ); return 0;

}

//----------------------------------------------------------------------

//----------------------------------------------------------------------

// g++ -O2 -o client.exe client.cpp -lsocket -lnsl

//----------------------------------------------------------------------

#include <stdio.h>

#include <stdlib.h>

#include <strings.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <unistd.h>

#include <netdb.h>

#include <sys/types.h>

//---------------------------------------------------------------------static void error ( char* msg ) { perror( msg ); exit( 0 );

}

//---------------------------------------------------------------------int main ( int argc, char* argv[] ) { if (argc < 3) { fprintf( stderr, "usage: %s hostname port \n", argv[0] ); exit( 0 );

}

//get port number from command line int portno = atoi( argv[2] );

//create an endpoint for communication int sockfd = socket( AF_INET, SOCK_STREAM, 0 ); if (sockfd < 0) error( "ERROR opening socket" );

//get host name from command line struct hostent* server = gethostbyname( argv[1] ); if (server == NULL) { fprintf( stderr, "ERROR, no such host \n" ); exit( 0 );

} struct sockaddr_in serv_addr; memset( &serv_addr, sizeof(serv_addr), 0 ); serv_addr.sin_family = AF_INET; memcpy( &serv_addr.sin_addr.s_addr, server->h_addr, server->h_length ); serv_addr.sin_port = htons( portno ); if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) error( "ERROR connecting" ); printf( "Please enter the message: " ); char buffer[256]; memset( buffer, sizeof(buffer), 0 ); fgets( buffer, sizeof(buffer)-1, stdin );

//fgets includes \n, so we'll remove it (if necessary) if (strlen(buffer) > 0 && buffer[strlen(buffer)-1] == '\n') buffer[ strlen(buffer)-1 ] = 0; int n = write( sockfd, buffer, strlen(buffer)+1 ); //+1 to include \0 if (n < 0) error( "ERROR writing to socket" ); memset( buffer, sizeof(buffer), 0 ); n = read( sockfd, buffer, sizeof(buffer)-1 ); if (n < 0) error( "ERROR reading from socket" ); printf( "%s \n", buffer ); return 0;

}

//----------------------------------------------------------------------

Sockets – client-side

(complete code)

SOCKETS – SERVER SIDE

Sockets – server-side

Sockets – server-side

Steps:

1.

socket()

 creates an endpoint for communication and returns a descriptor

2.

bind()

 this is called "assigning a name to a socket" when a socket is created with socket, it exists in a name space (address family) but has no name assigned

3.

listen()

To accept connections, a socket is first created with socket(), a willingness to accept incoming connections and a queue limit for incoming connections are specified with listen, and then the connections are accepted with accept().

4.

repeat forever:

1.

accept()

2.

fork() a child process that performs reads and/or writes as per ordinary file.

int accept ( int s, struct sockaddr* addr, socklen_t* addrlen );

It . . .

1.

extracts the first connection request on the queue of pending connections,

2.

creates a new connected socket with mostly the same properties as s,

3.

and allocates a new file descriptor for the socket, which is returned.

The newly created socket is no longer in the listening state.

The original socket s is unaffected by this call.

/**

* \file server2.cpp

* \author george j. grevera

* \brief A simple server in the internet domain using TCP. Runs on

#include <netinet/in.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/socket.h>

#include <unistd.h>

Sockets – server-side

* polaris (but not on scott).

* To compile: g++ -o server2.exe server2.cpp -lsocket

*/

#include <assert.h> static const int Port = 8090; static const bool Verbose = true;

//---------------------------------------------------------------------int main ( int argc, char* argv[] ) {

//create an endpoint for communication if (Verbose) puts( "socket()" ); int sockfd = socket( AF_INET, SOCK_STREAM, 0 ); assert( sockfd != -1 );

//assign a name to the socket struct sockaddr_in serv_addr;

Sockets – server-side memset( &serv_addr, 0, sizeof(serv_addr) ); serv_addr.sin_family

= AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port

= htons( Port ); if (Verbose) printf( "bind() port %d. \n", Port ); int ret = bind( sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr) ); assert( ret != -1 );

Sockets – server-side

//a willingness to accept incoming connections and a queue

// limit for incoming connections are specified with listen if (Verbose) puts( "listen()" ); ret = listen( sockfd, 5 ); assert( ret != -1 );

} for ( ; ; ) {

//extract the first connection request on the queue of

// pending connections, create a new connected socket with

// mostly the same properties as s, and allocate a new file

// descriptor for the socket, which is returned

Sockets – server-side if (Verbose) puts( "parent: accept()" ); struct sockaddr_in cli_addr; socklen_t clilen = sizeof( cli_addr ); int newsockfd = accept( sockfd, (struct sockaddr*)&cli_addr, &clilen ); assert( newsockfd != -1 ); if (Verbose) puts( "child: begin after fork()" ); close( sockfd ); if (Verbose) puts( "parent: fork()" ); int pid = fork(); if (pid==0) {

<child process code here> char buffer[ 256 ]; memset( buffer, 0, sizeof(buffer) );

} close( newsockfd ); //back in parent if (Verbose) puts( "child: read()" ); int n = read( newsockfd, buffer, sizeof(buffer)-1 ); assert( n != -1 ); return 0;

}

//---------------------------------------------------------------------if (Verbose) { printf( "child: here is the message: %s \n", buffer ); puts( "child: write()" );

} char* msg = "I got your message."; n = write( newsockfd, msg, strlen(msg)+1 ); //+1 to include \0 assert( n != -1 ); close( newsockfd ); if (Verbose) puts( "child: end" ); exit( 0 ); //end child

/**

* \file server2.cpp

* \author george j. grevera

* \brief A simple server in the internet domain using TCP. Runs on

* polaris (but not on scott).

* To compile: g++ -o server2.exe server2.cpp -lsocket

*/

#include <assert.h>

#include <netinet/in.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/socket.h>

#include <unistd.h> static const int Port = 8090; static const bool Verbose = true;

//---------------------------------------------------------------------int main ( int argc, char* argv[] ) {

//create an endpoint for communication if (Verbose) puts( "socket()" ); int sockfd = socket( AF_INET, SOCK_STREAM, 0 ); assert( sockfd != -1 );

//assign a name to the socket struct sockaddr_in serv_addr; memset( &serv_addr, 0, sizeof(serv_addr) ); serv_addr.sin_family

= AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port

= htons( Port ); if (Verbose) printf( "bind() port %d. \n", Port ); int ret = bind( sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr) ); assert( ret != -1 );

//a willingness to accept incoming connections and a queue

// limit for incoming connections are specified with listen if (Verbose) puts( "listen()" ); ret = listen( sockfd, 5 ); assert( ret != -1 ); for ( ; ; ) {

//extract the first connection request on the queue of

// pending connections, create a new connected socket with

// mostly the same properties as s, and allocate a new file

// descriptor for the socket, which is returned if (Verbose) puts( "parent: accept()" ); struct sockaddr_in cli_addr; socklen_t clilen = sizeof( cli_addr ); int newsockfd = accept( sockfd, (struct sockaddr*)&cli_addr, &clilen ); assert( newsockfd != -1 ); if (Verbose) puts( "parent: fork()" ); int pid = fork(); if (pid==0) { if (Verbose) puts( "child: begin after fork()" ); close( sockfd ); char buffer[ 256 ]; memset( buffer, 0, sizeof(buffer) ); if (Verbose) puts( "child: read()" ); int n = read( newsockfd, buffer, sizeof(buffer)-1 ); assert( n != -1 ); if (Verbose) { printf( "child: here is the message: %s \n", buffer ); puts( "child: write()" );

} char* msg = "I got your message."; n = write( newsockfd, msg, strlen(msg)+1 ); //+1 to include \0 assert( n != -1 );

} close( newsockfd ); if (Verbose) puts( "child: end" ); exit( 0 );

} close( newsockfd ); return 0;

}

//----------------------------------------------------------------------

Sockets – server-side

(complete code)

Demo

Run server on one system (brunel).

 ./server2.exe

 Waits for a message from the client, and then responds.

Run client (on same or different system).

 ./client.exe brunel 8090

 Prompts for a message, sends message to server, and then outputs response message from server.

Message Queues

Message queues (Unix/Linux)

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

MSGMAX (Linux) defines the max length of a message

(~8K).

Define your message(s).

 You may define many different messages of different lengths.

struct myMessage { long mtype;

};

//message type

//body of message (you decide)

Message queues (Unix/Linux)

► msgget - begin accessing (and create if necessary) a message queue int msgget ( key_t key, int msgflg );

► msgsnd - send (enqueue) a message int msgsnd ( int msqid, struct msgbuf* msgp, size_t msgsz, int msgflg );

► msgrcv - receive (dequeue) a message ssize_t msgrcv ( int msqid, struct msgbuf* msgp, size_t msgsz, long msgtyp, int msgflg );

► msgctl - misc. message queue control

Example

//file: m.h

//declare the message structure typedef struct { enum { mTypeA, mTypeB, mTypeC }; long mtype; char mtext[ 256 ];

} message_buf;

#define KEY 1234

Example (sender)

//file: mtx.cpp

fprintf( stderr, "msgget: msgget succeeded: msqid = %d \n", msqid );

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

// We'll send message type B message_buf sbuf; sbuf.mtype = sbuf.mTypeB; strcpy( sbuf.mtext, "Did you get this?" );

//size_t buf_length = strlen(sbuf.mtext) + 1 ; size_t buf_length = sizeof( message_buf );

#include "m.h" int main ( int argc, char* argv[] ) {

// Get the message queue id for the "name" 1234, which was created by

// the server.

key_t key = KEY; int msgflg = IPC_CREAT | 0666; fprintf( stderr, "\nmsgget: Calling msgget(%#lx,%#o)

\n", key, msgflg ); int msqid; if ((msqid = msgget(key, msgflg)) < 0) { perror( "msgget" ); exit( 1 );

}

// Send a message.

if (msgsnd(msqid, &sbuf, buf_length, IPC_NOWAIT) < 0)

{

} printf( "%d, %d, %s, %d\n", msqid, sbuf.mtype, sbuf.mtext, buf_length ); perror( "msgsnd" ); exit( 1 ); printf( "Message: \"%s\" Sent \n", sbuf.mtext );

} return 0;

//file mrx.cpp

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

#include <stdio.h>

#include <stdlib.h>

Example (receiver)

// Receive an answer of message type B.

message_buf rbuf; if (msgrcv(msqid, &rbuf, sizeof(rbuf), 0, 0) < 0)

{ perror( "msgrcv" ); exit( 1 );

}

#include "m.h" int main ( int argc, char* argv[] ) {

// Get the message queue id for the

"name" KEY, which was created by

// the server.

int msqid = msgget( KEY, 0666 ); if (msqid < 0) { perror( "msgget" ); exit( 1 );

}

}

// Print the answer.

printf( "%d %s \n", rbuf.mtype, rbuf.mtext ); exit( 0 );

Message queues (Windows)

Call MQOpenQueue to open the queue with send access.

Call MQSendMessage to send the message.

The MQReceiveMessage function allows you to read messages . When reading messages, you can either peek at (not removing them) or retrieve the messages (removing them) in the queue. Messages can be read either synchronously, asynchronously, or through a transaction.

Call MQCloseQueue to close the opened queue and free resources.

Demo (Unix)

mtx.exe

 Creates queue (if necessary, so run first).

 Queues up one message.

mrx.exe

 Dequeues a message (waits, otherwise).

Other IPC Mechanisms

Other IPC mechanisms:

Monitors

 A collection of procedures, variables, and data structures that are all grouped together in a special kind of module or package.

 Only one process can be active in a monitor at any instant.

Monitors and the (bounded) producerconsumer problem

Where do we see monitors?

“The Java programming language provides two basic synchronization idioms: synchronized methods and synchronized statements.”

- from http://download.oracle.com/javase/tutorial/essential/co ncurrency/syncmeth.html

Where do we see monitors?

“Synchronization is built around an internal entity known as the intrinsic lock or monitor lock. (The

API specification often refers to this entity simply as a "monitor.")”

- from http://download.oracle.com/javase/tutorial/essential/co ncurrency/locksync.html

Java support . . .

1.

synchronized methods

2.

synchronized statements (blocks)

SYNCHRONIZED METHODS

Synchronized methods

To make a method synchronized, simply add the synchronized keyword to its declaration: public class SynchronizedCounter { private int c = 0; public synchronized void increment ( ) public synchronized void decrement ( ) public synchronized int value ( )

{ c++; }

{ c--; }

{ return c; }

}

If count is an instance of SynchronizedCounter, then making these methods synchronized has two effects:

1.

First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.

2.

Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object.

This guarantees that changes to the state of the object are visible to all threads.

- from http://download.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

Locks in synchronized methods

When a thread invokes a synchronized method, it automatically acquires the intrinsic lock for that method's object and releases it when the method returns.

 The lock release occurs even if the return was caused by an uncaught exception.

- from http://download.oracle.com/javase/tutorial/essential/concurrency/locksync.html

Locks in synchronized methods

You might wonder what happens when a static synchronized method is invoked, since a static method is associated with a class, not an object.

In this case, the thread acquires the intrinsic lock for the

Class object associated with the class.

Thus access to class's static fields is controlled by a lock that's distinct from the lock for any instance of the class.

- from http://download.oracle.com/javase/tutorial/essential/concurrency/locksync.html

SYNCHRONIZED

STATEMENTS

Synchronized statements

public void addName ( String name )

{ synchronized (this) { lastName = name; nameCount++;

} nameList.add( name );

}

Single lock taken out on this entire object

(instance).

public class MsLunch { private long c1 = 0; private long c2 = 0; private Object lock1 = new Object(); private Object lock2 = new Object(); public void inc1 ( ) {

} synchronized (lock1) {

} c1++; Locks taken out on two different objects for finer control.

public void inc2 ( ) { synchronized (lock2) { c2++;

}

}

}

Other IPC mechanisms:

Message passing (MPI)

Barriers (also implemented in MPI and the pthread library)

Download