*** a/src/backend/postmaster/pgstat.c
--- b/src/backend/postmaster/pgstat.c
***************
*** 2563,2569 **** pgstat_bestart(void)
  	beentry = MyBEEntry;
  	do
  	{
! 		beentry->st_changecount++;
  	} while ((beentry->st_changecount & 1) == 0);
  
  	beentry->st_procpid = MyProcPid;
--- 2563,2569 ----
  	beentry = MyBEEntry;
  	do
  	{
! 		pgstat_increment_changecount_before(beentry);
  	} while ((beentry->st_changecount & 1) == 0);
  
  	beentry->st_procpid = MyProcPid;
***************
*** 2588,2595 **** pgstat_bestart(void)
  	beentry->st_appname[NAMEDATALEN - 1] = '\0';
  	beentry->st_activity[pgstat_track_activity_query_size - 1] = '\0';
  
! 	beentry->st_changecount++;
! 	Assert((beentry->st_changecount & 1) == 0);
  
  	/* Update app name to current GUC setting */
  	if (application_name)
--- 2588,2594 ----
  	beentry->st_appname[NAMEDATALEN - 1] = '\0';
  	beentry->st_activity[pgstat_track_activity_query_size - 1] = '\0';
  
! 	pgstat_increment_changecount_after(beentry);
  
  	/* Update app name to current GUC setting */
  	if (application_name)
***************
*** 2624,2635 **** pgstat_beshutdown_hook(int code, Datum arg)
  	 * before and after.  We use a volatile pointer here to ensure the
  	 * compiler doesn't try to get cute.
  	 */
! 	beentry->st_changecount++;
  
  	beentry->st_procpid = 0;	/* mark invalid */
  
! 	beentry->st_changecount++;
! 	Assert((beentry->st_changecount & 1) == 0);
  }
  
  
--- 2623,2633 ----
  	 * before and after.  We use a volatile pointer here to ensure the
  	 * compiler doesn't try to get cute.
  	 */
! 	pgstat_increment_changecount_before(beentry);
  
  	beentry->st_procpid = 0;	/* mark invalid */
  
! 	pgstat_increment_changecount_after(beentry);
  }
  
  
***************
*** 2666,2672 **** pgstat_report_activity(BackendState state, const char *cmd_str)
  			 * non-disabled state.  As our final update, change the state and
  			 * clear fields we will not be updating anymore.
  			 */
! 			beentry->st_changecount++;
  			beentry->st_state = STATE_DISABLED;
  			beentry->st_state_start_timestamp = 0;
  			beentry->st_activity[0] = '\0';
--- 2664,2670 ----
  			 * non-disabled state.  As our final update, change the state and
  			 * clear fields we will not be updating anymore.
  			 */
! 			pgstat_increment_changecount_before(beentry);
  			beentry->st_state = STATE_DISABLED;
  			beentry->st_state_start_timestamp = 0;
  			beentry->st_activity[0] = '\0';
***************
*** 2674,2681 **** pgstat_report_activity(BackendState state, const char *cmd_str)
  			/* st_xact_start_timestamp and st_waiting are also disabled */
  			beentry->st_xact_start_timestamp = 0;
  			beentry->st_waiting = false;
! 			beentry->st_changecount++;
! 			Assert((beentry->st_changecount & 1) == 0);
  		}
  		return;
  	}
--- 2672,2678 ----
  			/* st_xact_start_timestamp and st_waiting are also disabled */
  			beentry->st_xact_start_timestamp = 0;
  			beentry->st_waiting = false;
! 			pgstat_increment_changecount_after(beentry);
  		}
  		return;
  	}
***************
*** 2695,2701 **** pgstat_report_activity(BackendState state, const char *cmd_str)
  	/*
  	 * Now update the status entry
  	 */
! 	beentry->st_changecount++;
  
  	beentry->st_state = state;
  	beentry->st_state_start_timestamp = current_timestamp;
--- 2692,2698 ----
  	/*
  	 * Now update the status entry
  	 */
! 	pgstat_increment_changecount_before(beentry);
  
  	beentry->st_state = state;
  	beentry->st_state_start_timestamp = current_timestamp;
***************
*** 2707,2714 **** pgstat_report_activity(BackendState state, const char *cmd_str)
  		beentry->st_activity_start_timestamp = start_timestamp;
  	}
  
! 	beentry->st_changecount++;
! 	Assert((beentry->st_changecount & 1) == 0);
  }
  
  /* ----------
--- 2704,2710 ----
  		beentry->st_activity_start_timestamp = start_timestamp;
  	}
  
! 	pgstat_increment_changecount_after(beentry);
  }
  
  /* ----------
***************
*** 2734,2746 **** pgstat_report_appname(const char *appname)
  	 * st_changecount before and after.  We use a volatile pointer here to
  	 * ensure the compiler doesn't try to get cute.
  	 */
! 	beentry->st_changecount++;
  
  	memcpy((char *) beentry->st_appname, appname, len);
  	beentry->st_appname[len] = '\0';
  
! 	beentry->st_changecount++;
! 	Assert((beentry->st_changecount & 1) == 0);
  }
  
  /*
--- 2730,2741 ----
  	 * st_changecount before and after.  We use a volatile pointer here to
  	 * ensure the compiler doesn't try to get cute.
  	 */
! 	pgstat_increment_changecount_before(beentry);
  
  	memcpy((char *) beentry->st_appname, appname, len);
  	beentry->st_appname[len] = '\0';
  
! 	pgstat_increment_changecount_after(beentry);
  }
  
  /*
***************
*** 2760,2769 **** pgstat_report_xact_timestamp(TimestampTz tstamp)
  	 * st_changecount before and after.  We use a volatile pointer here to
  	 * ensure the compiler doesn't try to get cute.
  	 */
! 	beentry->st_changecount++;
  	beentry->st_xact_start_timestamp = tstamp;
! 	beentry->st_changecount++;
! 	Assert((beentry->st_changecount & 1) == 0);
  }
  
  /* ----------
--- 2755,2763 ----
  	 * st_changecount before and after.  We use a volatile pointer here to
  	 * ensure the compiler doesn't try to get cute.
  	 */
! 	pgstat_increment_changecount_before(beentry);
  	beentry->st_xact_start_timestamp = tstamp;
! 	pgstat_increment_changecount_after(beentry);
  }
  
  /* ----------
***************
*** 2839,2845 **** pgstat_read_current_status(void)
  		 */
  		for (;;)
  		{
! 			int			save_changecount = beentry->st_changecount;
  
  			localentry->backendStatus.st_procpid = beentry->st_procpid;
  			if (localentry->backendStatus.st_procpid > 0)
--- 2833,2842 ----
  		 */
  		for (;;)
  		{
! 			int			before_changecount;
! 			int			after_changecount;
! 
! 			pgstat_save_changecount_before(beentry, before_changecount);
  
  			localentry->backendStatus.st_procpid = beentry->st_procpid;
  			if (localentry->backendStatus.st_procpid > 0)
***************
*** 2856,2863 **** pgstat_read_current_status(void)
  				localentry->backendStatus.st_activity = localactivity;
  			}
  
! 			if (save_changecount == beentry->st_changecount &&
! 				(save_changecount & 1) == 0)
  				break;
  
  			/* Make sure we can break out of loop if stuck... */
--- 2853,2861 ----
  				localentry->backendStatus.st_activity = localactivity;
  			}
  
! 			pgstat_save_changecount_after(beentry, after_changecount);
! 			if (before_changecount == after_changecount &&
! 				(before_changecount & 1) == 0)
  				break;
  
  			/* Make sure we can break out of loop if stuck... */
***************
*** 2927,2938 **** pgstat_get_backend_current_activity(int pid, bool checkUser)
  
  		for (;;)
  		{
! 			int			save_changecount = vbeentry->st_changecount;
  
  			found = (vbeentry->st_procpid == pid);
  
! 			if (save_changecount == vbeentry->st_changecount &&
! 				(save_changecount & 1) == 0)
  				break;
  
  			/* Make sure we can break out of loop if stuck... */
--- 2925,2941 ----
  
  		for (;;)
  		{
! 			int			before_changecount;
! 			int			after_changecount;
! 
! 			pgstat_save_changecount_before(vbeentry, before_changecount);
  
  			found = (vbeentry->st_procpid == pid);
  
! 			pgstat_save_changecount_after(vbeentry, after_changecount);
! 
! 			if (before_changecount == after_changecount &&
! 				(before_changecount & 1) == 0)
  				break;
  
  			/* Make sure we can break out of loop if stuck... */
*** a/src/include/pgstat.h
--- b/src/include/pgstat.h
***************
*** 16,21 ****
--- 16,22 ----
  #include "libpq/pqcomm.h"
  #include "portability/instr_time.h"
  #include "postmaster/pgarch.h"
+ #include "storage/barrier.h"
  #include "utils/hsearch.h"
  #include "utils/relcache.h"
  
***************
*** 714,719 **** typedef struct PgBackendStatus
--- 715,726 ----
  	 * st_changecount again.  If the value hasn't changed, and if it's even,
  	 * the copy is valid; otherwise start over.  This makes updates cheap
  	 * while reads are potentially expensive, but that's the tradeoff we want.
+ 	 *
+ 	 * The above protocol needs the memory barriers to ensure that
+ 	 * the apparent order of execution is as it desires. Otherwise,
+ 	 * for example, the CPU might rearrange the code so that st_changecount
+ 	 * is incremented twice before the modification on a machine with
+ 	 * weak memory ordering. This surprising result can lead to bugs.
  	 */
  	int			st_changecount;
  
***************
*** 745,750 **** typedef struct PgBackendStatus
--- 752,794 ----
  	char	   *st_activity;
  } PgBackendStatus;
  
+ /*
+  * Macros to load and store st_changecount with the memory barriers.
+  *
+  * pgstat_increment_changecount_before() and
+  * pgstat_increment_changecount_after() need to be called before and after
+  * PgBackendStatus entries are modified, respectively. This makes sure that
+  * st_changecount is incremented around the modification.
+  *
+  * Also pgstat_save_changecount_before() and pgstat_save_changecount_after()
+  * need to be called before and after PgBackendStatus entries are copied into
+  * private memory, respectively.
+  */
+ #define pgstat_increment_changecount_before(beentry)	\
+ 	do {	\
+ 		beentry->st_changecount++;	\
+ 		pg_write_barrier();	\
+ 	} while (0)
+ 
+ #define pgstat_increment_changecount_after(beentry)	\
+ 	do {	\
+ 		pg_write_barrier();	\
+ 		beentry->st_changecount++;	\
+ 		Assert((beentry->st_changecount & 1) == 0);	\
+ 	} while (0)
+ 
+ #define pgstat_save_changecount_before(beentry, save_changecount)	\
+ 	do {	\
+ 		save_changecount = beentry->st_changecount;	\
+ 		pg_read_barrier();	\
+ 	} while (0)
+ 
+ #define pgstat_save_changecount_after(beentry, save_changecount)	\
+ 	do {	\
+ 		pg_read_barrier();	\
+ 		save_changecount = beentry->st_changecount;	\
+ 	} while (0)
+ 
  /* ----------
   * LocalPgBackendStatus
   *
